Keeping a long-term reference to an IOS AddressBook entry
Asked Answered
P

4

16

Given that an ABRecordID can change between cloud syncs and under other circumstances out of my control, how can I maintain a long-term reference to an IOS address book record?

Apple provides the following guidance:

"The recommended way to keep a long-term reference to a particular record is to store the first and last name, or a hash of the first and last name, in addition to the identifier. When you look up a record by ID, compare the record’s name to your stored name. If they don’t match, use the stored name to find the record, and store the new ID for the record."

But I don't understand this guidance. If the address book can have duplicate names in it AND since users can modify the name in a record how could this advice work?

For example, if the user modifies the name of an address book record my routine will fail to find it by ABRecordID so if I think search by the name hash I stored couldn't I find a duplicate name instead of the new ABRecordID for that specific record I previously referenced?

In the end, what is the BEST way to get a long-term reference to an IOS AddressBook record? And if the above advice really does work what am I missing?

Phifer answered 8/2, 2013 at 0:24 Comment(3)
Could you be a little more specific on what you are trying to accomplish with the permanent id? If it to link it to another service, database, perhaps a better approach would be to create something on the contact you can track it with. The really sad thing is this is not a problem on the mac. See : blog.clickablebliss.com/2011/11/07/… for more infoNephrectomy
@RichDominelli I am trying to associate application settings data with each contact that can survive a restore or cloud sync and of course renames and updates.Phifer
Right now iOS does not support the uuid for each record nor does it support custom fields. You could try generating a hash but as you indicated its not perfect. You could also put in a custom label phone number which is unique to each record but again the user can easily break it.Nephrectomy
R
23

The most robust (yet not completely failsafe) approach would be to come up with a priority ranking of ABRecord fields and store as much from that list as is available, along with the ABRecordID, into your own (hashed) private record format. When retrieving a private record (or at another convenient time), you can verify that the private record matches the ABRecord and work through a series of fallback checks to ensure it's accurate.

Example priority ranking:

  1. ABRecordID
  2. FirstName
  3. LastName
  4. PhoneNumber
  5. ZipCode

When retrieving a record you can first match the ABRecordID. If that returns no results, you can do a search for FirstName + LastName. You can then match those results against PhoneNumber... etc. In this way you could potentially distinguish between 2 Bob Smiths, as they may have different phone numbers (or one may not have a phone number). Of course, depending on how long your priority list is, the more robust this mechanism will be.

The last resort would be prompting the user to distinguish between 2 Bob Smiths with brand new ABRecordID's whose records are otherwise identical -- after all, such an inconvenient prompt would be far more friendly than allowing the User to contact the wrong Bob Smith (and as I said, would be a last resort).

This solution for AB may involve some synchronization issues, however.

This is a familiar problem for anyone who has worked with the iOS Media Player. Specifically MPMediaItems in the User's Music Library have a property MPMediaItemPropertyPersistentID which the docs describe as:

The value is not guaranteed to persist across a sync/unsync/sync cycle.

In other words, the PersistentID is not guaranteed to be persistent. Solutions for this include doing similar fallback checks on MediaItem properties.

Rensselaerite answered 11/2, 2013 at 16:44 Comment(3)
how about make all the property together into a string,then make md5 encoding.You just to check md5 code is equal.Triangle
@Triangle that solution will fail if the user modifies any information in the record.Rensselaerite
Is this still relevant in latest API version? The docs that said "abreocord is not consistent across devices" are now archived. The latest docs only say that ABRecord#uniqueId is unique and there doesn't seem to more info.Plat
W
3

The RecordID only get changed either on delete or reset, when this is done all the new record(s) will have new createdProperty and modifiedProperty as well.

  1. While I am reading the address book for the first time, I will save all entries of the record along with RecordID in my database.

  2. I will save the last time the contacts synced from contacts to my database(name it something: lastSyncedTime) and store it some where.

I am done with syncing the contacts for the first time, now do the following for syncing anytime in future.

while Iterating through all records,

  1. check createdTime(kABPersonCreationDateProperty) vs lastSyncedTime. If createdTime > lastSyncedTime, store the recordID in a "newRecords" NSArray.

  2. If !(step 1) then check modifiedDate(kABPersonModificationDateProperty) vs lastSyncedTime. If modifiedDate > lastSyncedTime, then store the recordID in a "modifiedRecords" NSArray.

  3. if !(1) && !(2) store all recordID in a "unModifiedRecords".

Now I will read all the contacts from my local database,

  1. I will delete all local database records that are not find either in "modifiedRecords" or in "unModifiedRecords".

  2. I will update all "modifiedRecords" in the local database.

  3. I will create new records for all records in "newRecords".

  4. Update the lastSyncedTime accordingly.

Weigel answered 29/8, 2013 at 10:41 Comment(3)
Yes good. But this method not worked for the ABRecordRef group.Because the group don't have any date related property...Triangle
and if the last synced time is use local date([NSDate date]),if the user changed the date.this method not work.Triangle
and you may just need to compare the last modified time. when the record is crate,the create time is equal to the last modified time.Triangle
H
0

The documentation is communicating to you that you can't count on ABRecordID as a permanent identifier.

Consider this scenario: The user has a record for "Bob Smith". The user then deletes his "Bob Smith" record and then imports his contacts from his computer (creating a new ID) through iTunes sync.

So if you want to keep a permanent reference to an existing contact, you can keep a reference to the name and id as a hint that it is the same record you used before- but there is no real permanent reference.

If you keep a permanent reference to an address book contact, you must always be ready to deal with the fact that it may not be the same contact you used before.

Hewe answered 8/2, 2013 at 6:11 Comment(5)
Well yes, I think that's what I said in my post and why I quoted the programming guide. My question is how best to keep a long term reference. If Bob Smith is deleted then recreated, I can handle that using their advice. If a device is restored or a MobileMe reset changes every ID then it seems as though the Apple advice would not work. So (a) am I right in assuming their advice wont work and (b) if I am right then what approach to people use to properly update the ids or what other methods do they use to keep a long term reference considering that the AddressBook allows duplicate names?Phifer
(A)Their advice works and is the best practice - you will usually be able to tie back to your stored ID and name combo. (B)You just always have to assume the worst case scenario is possible (that the record no longer is the record it was the last time your app referenced it and there may be duplicate records matching the stored name now).Hewe
Just so I understand, there is no method that prevents the following from happening? There are two Bob Smith's in the Address Book. I store the ABRecordID and name hash for both. Then I associate some of my app metadata with one. The iPhone is reset and all ABRecordIDs are regenerated. NOW I can NOT know for which Bob Smith I have associated meta data, correct? If I fall back on a name search I will get an arbitrary Bob Smith.Phifer
Yes. You always have to be ready for the worst case scenario. Think of it this way - it's the USER's address book - and you are a guest looking at it. They may rip out the pages at any time. So if your app launches and notices the records are different, you have to plan a workflow for graceful recovery.Hewe
-1 there is no way but that was already in the question... with the comments this would be an answer IMOCaramelize
U
0

Refer : https://developer.apple.com/library/ios/documentation/ContactData/Conceptual/AddressBookProgrammingGuideforiPhone/Chapters/DirectInteraction.html#//apple_ref/doc/uid/TP40007744-CH6-SW2

Clearly tells you how to handle it.

Urbana answered 2/12, 2015 at 13:20 Comment(1)
Note that link-only answers are discouraged, SO answers should be the end-point of a search for a solution (vs. yet another stopover of references, which tend to get stale over time). Please consider adding a stand-alone synopsis here, keeping the link as a reference.Dispossess

© 2022 - 2024 — McMap. All rights reserved.