Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

CNContacts framework possible bug with phone identifier?

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

like image 698
MegaManX Avatar asked Sep 29 '17 13:09

MegaManX


2 Answers

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.

like image 151
Jeremy Brown Avatar answered Nov 13 '22 23:11

Jeremy Brown


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.

like image 2
carlos21 Avatar answered Nov 14 '22 01:11

carlos21