Matt Legend Gemmell Modesty is Lying

Mac OS X Cocoa and iPhone Development Services available at Instinctive Code.
Favorites icon
Favorites for iPhone
Speed-dial with style.
Mac OS X Cocoa and iPhone Developer for hire
Sheercore Comics - Geeks with Swords!

Other Pages

Categories

Posted
31 October 2008 @ 11am

Categories
Development

Tags
, , , , , , , , , , , ,

iPhone dev tips for synced contacts

I wanted to share a couple of brief tips for developers who are working with contacts on iPhone and iPod touch, where the user has enabled syncing with services like MobileMe or Microsoft Exchange.

These are lessons I’ve learned when diagnosing and fixing a couple of bugs which my (most beloved) users of Favorites have reported. If you’re an iPhone developer who’s doing things with the Address Book API, you may want to take note.


Unique record-identifiers change after MobileMe sync

If you’re storing references to the user’s contacts, you’re probably doing so by keeping the record-IDs, on the assumption that these are unique (they are) and will not change for a given contact (wrong). If the user enables MobileMe sync for their contacts, there’s a very high chance that the record-IDs will change. This is presumably to enforce a globally-unique (across all synced devices) identifier in the cloud. It’s also pretty annoying.

One solution would be, when you’re storing a contact’s ID, also grab their full composite name (via ABRecordCopyCompositeName()) and store that too. When you’re looking up a contact later, if the ID-based look-up fails (ABAddressBookGetPersonWithRecordID()), fall back on a composite-name-based look-up instead (ABAddressBookCopyPeopleWithName()). You can also take note of more fields, and do more advanced matching if you feel it’s necessary. If you find a suitable contact, be sure to update your copy of the ID.

It would be nice if Apple fixed this somehow (such as divorcing the device-local unique identifiers from the global cloud-based identifiers), but for now you’ll have to do a little bit of work to ensure your contact-references behave as the user expects.

Labels can be NULL for Exchange contacts

If your user syncs with Microsoft Exchange, the labels (like “work” or “mobile” or whatever) for each phone-number and email address can and often will be NULL (and I mean really NULL, not just an empty string). This can be unexpected, because it’s not possible to create a contact whose numbers/email addresses have a NULL label using the Address Book (Mac) or Contacts (iPhone) UIs.

Just be sure to code defensively, and not assume that a label will always exist even though there’s a number or email address. It’s a very small additional check which you should probably be doing anyway, but I thought it was worth pointing out because it’s perhaps not something you’d otherwise expect.

If you have any other tips relating to dealing with contacts on iPhone from a developer’s perspective, feel free to post them below.


13 Comments

Ahruman
31 October 2008 @ 11am

It’s funny, I was thinking about the ID problem a couple of weeks ago, even though I’m not working on anything relevant. It didn’t take me long to conclude that the DB should be tracking sets of IDs rather than a single value. Pity I didn’t work for Apple back when they made the address book, eh? :-)


Steve (mgprot)
31 October 2008 @ 12pm

Thanks for sharing! It’s comforting to know that other people are banging their heads against the same walls that you are :-)

In addition to the composite name, I also store the first and last names separately. The problem being that the RecordID’s are by default a simple 32 bit int sequence starting at 1. I haven’t been able to test this yet, but the ID’s are documented as only being unique -per device-. I expect that moving or syncing contacts from one device to another will result in overlapping ID ranges. In this case, getting a record by RecordID could well succeed but give you the wrong person. oops :-)

Also, if ABAddressBookCopyPeopleWithName fails when using the composite name (for example, because a person changed their jobs – new company name, new composite name *sigh*) you can fall back further to using just their actual name. (don’t ask me what do to when someone marries between syncs)

Quite a lot of work to enhance contact data with application data and keep them synchronized. (I’m really glad we can at least use background threads for this ;-)


Ahruman
31 October 2008 @ 1pm

Incrementing numbers suck. UUIDs for the reasonably high degree of win.


David Aspinall
31 October 2008 @ 3pm

I have not had an opportunity to investigate this, but is the uniqueId (integer) different from the ABRecord: kABUIDProperty? Could you set the kABUIDProperty? Would it persist through a sync?

What about adding a hidden custom property? I know this is a little counter intuitive but this is almost storing most of your favorites information in the address book rather than your own database.

Oh you could also add a custom URL scheme and store everything in the person url property….


Matt Legend Gemmell
31 October 2008 @ 4pm

HI David,

Address Book on the iPhone is quite different to its cousin on Mac OS X. That property you mentioned is only present in the OS X version of the API, for example, and you’re also limited to the pre-defined properties on iPhone – you can’t add arbitrary new ones as you can on OS X.

Regarding storing relevant info in a standard field like the URL field, that would possibly work but would be messy when those URLs were synced back to other devices.

Also, the only programmatic ways to search for contacts via the iPhone API are by full (composite) name or by record-ID; you cannot search by arbitrary fields, as you can on OS X. Thus, locating a contact for a given favorite using any other field would involve iteration through all contacts, which would be very inefficient.


iBranc
23 November 2008 @ 6pm

This is further complicated because you can create multiple address book entries with the same name. There is nothing stopping a person from having 2 identically named records that hold different information. i.e. you can have 2 contacts named Kate Bell with different Mobile numbers.

This is a bit of a disaster really. Nothing is 100%. Even presenting a user with a pick list if there are 2 results after doing a name search would leave them guessing which one they really meant.

Also, for those considering ‘background updates’ keep in mind that there are more users than you would anticipate that have many thousands of contacts. This is both memory intensive and time consuming to sync.


iBranc
2 December 2008 @ 2am

Matt – not sure how much you played around with this, but getting a person by Composite Name with the function ABAddressBookCopyPeopleWithName() doesn’t actually work in all cases. It only works for the simplest form of a name, but will not work if they use other fields such as suffix or middle name. In the default addressbook in xcode simulator, you can get Anna Haro, but you can’t get Daniel Higgins Jr. or Hank M. Zakroff. The Jr. and M. throw it off.

I’m quite amazed at the size of this hole. Its pretty much a killer for my app.


Chris
5 January 2009 @ 8pm

Unfortunately, Apple’s MobileMe sync doesn’t even work properly for Apple. Can we band together and ask Apple to fix this? I’ve used MobileMe and .Mac since they were first available, and constantly have to back up and refresh my contacts as they get mangled through syncing. It’s frustrating. I have thousands of contacts as I run my own Mac/iPhone software development firm…

To Apple’s credit, it is a difficult problem, complicated by the need to support third party sources like Exchange/Outlook. Every device has its own method of uniquely identifying records, which become meaningless when comparing/syncing with other sources. Non-Apple devices discard, ignore, or corrupt this metadata.

I personally think Apple with its deep pockets should fund an open standard for storing contacts that everyone can adopt. Even Microsoft. There’s no excuse for not solving this problem. If computers can sequence the human genome, model global weather patterns, and calculate PI to tons of decimal places… they ought to be able to handle my contacts better than an old-fashioned Rolodex. :-)


Paul Collins
12 January 2009 @ 4am

Matt, thanks for mentioning that Exchange-synced NULL label issue. That one bit me and finding your post helped pin down the problem.


sym
27 February 2009 @ 4am

Once the contact in iphone is synced with Microsoft Exchange, programming on contact may fail with no error notification. It means when I try to set an email to an existing contact with custom label. The code execute corrrectly(&errror parameter will be null after operation) but the email is not added to that contact actually.
Any idea about it?


Jon Nathan
4 March 2009 @ 10am

Has there been any improvement on the unique ID issue? Browsing the files in the iPhone backup, the file (from the iPhone):

/Library/Preferences/com.apple.mobilephone.speeddial.plist

lists the favorites from the phone app. This file contains an array of dicts that include the simple ABIdentifier as well as additional keys for ABDatabaseUUID (a true UUID), Label, Name, Property, Value, and also a key-value pair named ABUid which appears to also be a simple integer (instead of a UUID). Any ideas where this ABUid value comes from or where it is stored for use as a key to find a unique contact?


terkoz
14 May 2009 @ 3am

This is further complicated because you can create multiple address book entries with the same name. There is nothing stopping a person from having 2 identically named records that hold different information. i.e. you can have 2 contacts named Kate Bell with different Mobile numbers


Pankaj
8 June 2009 @ 6am

Hello All,

I am developing an iPhone application, which requires to know the running device name and phone number. Is there a way to achieve this through address book. I am successfully able to read the device address book.

Does the address book has an device owners phone entry n it, and if it does then how can we differ it from other contacts?

Looking forward for the reply.

Thanks,
Pankaj


Leave a Comment

Gemmell Inside What have you tried?