2

MY GOAL is to allow the users to create a contact using the standard UI (ABPersonViewController) but give them the choice to add it to the addressbook or to store it locally (in my CoreData db). As such, I need to do one of the following:

  • Store a copy of an ABRecord as NSData in my own DB and always work on that copy.
  • Store a representation of an ABRecord (vCard, proprietary format, other...) and convert to/from that representation whenever the user wants to edit a contact (so as to provide an ABRecord to the ABPersonViewController).

MY PROBLEM is that I cannot figure out a way to create records without adding them to the user's address book.

SOME CONTEXT

In the Address Book Programming Guide for iOS (link here), Apple's documentation states:

Even though records are usually part of the Address Book database, they can also exist outside of it. This makes them a useful way to store contact information your application is working with.

Which, of course, sounds perfect for what I need to do. But it does not give any instructions about ways to create ABRecords outside of an Addressbook.

The API only seems to provide ways to create then in a specified source (ABPersonCreateInSource) or in the default source (ABPersonCreate). On top of that, although the documentation says to call ABAddressBookAddRecord to add the created record to the addressbook, my tests show that the record is added anyways ! (Maybe it's added by the ABPersonViewController, I haven't checked).

I have searched a lot on internet and, although a few people have asked similar questions, nobody seems to have answered in a way that actually works ;-)

But I've seen several apps do this so I'm confident that it's possible.

MY QUESTION: How would you do this ?

Valentin Lorentz
  • 9,556
  • 6
  • 47
  • 69

1 Answers1

1

If you don't want to add an address to your address book, when using AddressBook.framework then just create the record (e.g. ABPersonCreate) but do not call ABAddressBookAddRecord followed by ABAddressBookSave, and it won't be stored in your address book. Only if you explicitly add and save the record will it be stored in your address book.

But, as you surmised, if you use AddressBookUI.framework (either edit and save a record in ABPersonViewController or save record from ABNewPersonViewController), then it will be saved in your address book.

If you really want to use AddressBookUI.framework, you could, theoretically, use ABNewPersonViewController, and then in your ABNewPersonViewControllerDelegate method newPersonViewController:didCompleteWithNewPerson:, if the ABRecordRef is not NULL, you could then remove that record with ABAddressBookRemoveRecord and save via ABAddressBookSave, and the record that was added would be removed. That strikes me as a particularly inelegant approach, but it works.

But if you don't need AddressBookUI.framework, then you can very easily create ABRecordRef records and just not explicitly add them to your address book, and you'll be fine.

Rob
  • 415,655
  • 72
  • 787
  • 1,044
  • Thanks for your answer, @Rob. It does sound inelegant but if it adequately circumvents a limitation (IMHO) of the framework, I'll use it until I have time to code a custom UI for that. However it does not completely address my request: what would be the best/appropriate way to store the contacts in my app's core data ? How do we go from ABRecordRef (or ABPersonRef) to NSData or something similar, ideally without enumerating each and every field that exists in a contact ? Thanks :) – Jérôme Lasserre Aug 22 '14 at 00:36
  • I know it's not the answer you're looking for, but the counsel I've seen online is to go through that annoying enumeration of all of the properties and then store those values in Core Data. The problem is that `ABRecordRef` is an opaque object for which you can't employ the usual seamless archive/serialization patterns. The alternative is `ABPersonCreateVCardRepresentationWithPeople()`, but it would then be hard to do queries against CoreData looking for records matching particular criteria. The VCF process will require less code, but will probably be less flexible. It's up to you. – Rob Aug 22 '14 at 01:17
  • Thanks again, @Rob :) I implemented the solution you suggested. Creating a new contact + immediately removing it from the addressbook works as expected. Saving to CoreData through vCard as well. Only problem remaining is that users can't **edit** that contact later without adding it again to the addressbook (thanks to ABPersonViewController). I could handle this case in the AddressBookExternalChangeCallback() but this is getting _too_ inelegant and I know I will run into issues where the user managed to quit the app between two important steps and break that fragile add-then-delete pattern... – Jérôme Lasserre Aug 23 '14 at 03:54
  • In any case, I'll accept your answer because it perfectly addresses my original issue. It's just unfortunate that Apple's API is so restrictive in this case. – Jérôme Lasserre Aug 23 '14 at 03:56
  • Did iOS 8 change anything as relates to this issue? – SAHM Feb 09 '15 at 20:05
  • @SAHM Not that I'm aware of. If you use `ABNewPersonViewController`, record is still added. – Rob Feb 09 '15 at 20:17
  • I just found this on the ABPerson Reference page: "Person records don’t necessarily have to be stored in the Address Book database. You can use person records as a way to group contact information in memory and present it to the user through, for example, a person view controller (ABPersonViewController)." https://developer.apple.com/library/ios/documentation/AddressBook/Reference/ABPersonRef_iPhoneOS/index.html – SAHM Feb 09 '15 at 21:00
  • We were talking about `ABNewPersonViewController` for presenting a UI to creating a record (and that will be added to address book), not `ABPersonViewController`. – Rob Feb 09 '15 at 21:03