Recently I have switched from old ABAddressBook framework to new CNContacts. In my project I synchronize contacts from native with my own core data contacts. For this I use contact identifier and phone identifiers to synchronize phone numbers.
But I have observed interesting thing, when i try to edit the contact, I call this line of code
func getContact() -> CNContact? {
let contactStore = CNContactStore()
guard let contactRecord = try? contactStore.unifiedContact(withIdentifier: "8222B6F1-DE99-4099-82A4-47EAB9206A94:ABPerson", keysToFetch: [CNContactViewController.descriptorForRequiredKeys()]) else {
return nil
}
return contactRecord
}
@IBAction func showContact() {
let contactViewController = CNContactViewController(forNewContact: self.getContact())
contactViewController.delegate = self
contactViewController.title = "New Contact"
let navigationController = UINavigationController(rootViewController: contactViewController)
navigationController.navigationBar.isTranslucent = false
self.present(navigationController, animated: true, completion: nil)
}
func contactViewController(_ viewController: CNContactViewController, didCompleteWith contact: CNContact?) {
let newContact = self.getContact()
viewController.dismiss(animated: false, completion: nil)
}
It is really simple. But if in CNContactViewController I edit user photo, phone identifiers will change, even though I did no editing to phone numbers in this controller. The phone identifier can easily be printed like this:
po newContact?.phoneNumbers.first?.identifier
This really messes up my sync, since user will maybe just change photo, but identifiers for phone numbers will change, and I will have no way to know what happened. This identifier will not change if I edit some other data, like persons name, company etc... It will remain the same even if I edit the phone to some other value. But for some reason changing the photo messes it completely up.
Has anyone else observed this?
Here is link to sample project to test this https://drive.google.com/file/d/0B9ngBRq15jSuZTBYNVJCaVJ5WGc/view?usp=sharing
EDIT: I tested this on real phone
I tried your sample project on an iPhone 8 simulator but can't seem to reproduce the issue. Here's the output right after I set an initial contact photo:
(lldb) po newContact?.phoneNumbers.first?.identifier
▿ Optional<String>
- some : "E5D4EDC2-B6FC-4E86-9AF0-F6B78BAF41E5"
(lldb) po oldContact?.phoneNumbers.first?.identifier
▿ Optional<String>
- some : "E5D4EDC2-B6FC-4E86-9AF0-F6B78BAF41E5"
And after I tap the button again and set a different photo as contact photo:
(lldb) po oldContact?.phoneNumbers.first?.identifier
▿ Optional<String>
- some : "E5D4EDC2-B6FC-4E86-9AF0-F6B78BAF41E5"
(lldb) po newContact?.phoneNumbers.first?.identifier
▿ Optional<String>
- some : "E5D4EDC2-B6FC-4E86-9AF0-F6B78BAF41E5"
Those all look the same to me. Only thing I did to your project was change the lookup in getContact() to an identifier that exists in my own contacts database.
I uploaded an example of how to create a new contact and how to edit it
https://drive.google.com/file/d/0B7OUqtQ1nSxjb3lFTFA5WnlGdFk/view?usp=sharing
For creating a new contact I'm using:
let newContact = CNMutableContact()
newContact.givenName = "Jhonny"
newContact.nickname = "Jhonny"
newContact.familyName = "My Family"
newContact.phoneNumbers.append(CNLabeledValue(label: "Home", value: CNPhoneNumber(stringValue: "555-123-4567")))
let contactViewController = CNContactViewController(forNewContact: newContact)
contactViewController.delegate = self
contactViewController.title = "New Contact"
let navigationController = UINavigationController(rootViewController: contactViewController)
self.present(navigationController, animated: true, completion: nil)
Pay attention to this line
let contactViewController = CNContactViewController(forNewContact: newContact)
For editing the contact I'm using:
let contactViewController = CNContactViewController(for: contactRecord)
contactViewController.delegate = self
contactViewController.title = "Edit Contact"
let navigationController = UINavigationController(rootViewController: contactViewController)
self.present(navigationController, animated: true, completion: nil)
Again, pay attention to this line
let contactViewController = CNContactViewController(for: contactRecord)
I believe the problem is the way to call CNContactViewController. The constructor is different for creating and editing. In the demo, you'll see in the console log that the phone number identifier remains intact even if you edit the photo or anything else.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With