Swift OSX CNContact.organizationName crash in High Sierra

294 views Asked by At

My OSX app allows the user to select a contact from their contacts list and loads the details into a Customer record. I am using CNContactPicker to retrieve a contact into a CNContact record. One of the fields I need to retrieve is organizationName. This works perfectly in OS's prior to High Sierra, but upon upgrading to High Sierra it will crash. All other CNContact fields can be retrieved with no issue (e.g. names, email, address etc). I do have permissions requested in my info.plist file.

It makes no difference if the Contact does/does not have an Organization Name.

Not much to show in terms of code:

// This fails on 1st line - any reference to organizationName causes failure
if (contact.organizationName != "") {
        self.name = contact.organizationName
}

// This works
if (contact.givenName != "") {
        self.name = contact.givenName
}

// This works
if (contact.contactType == CNContactType.organization) {
    // Do something
}

The actual error is: [General] A property was not requested when contact was fetched.

I would like to know what has changed in the OS to cause this error, and if there is a solution or workaround please.

1

There are 1 answers

0
N Gill On BEST ANSWER

I submitted a bug report with Apple and received the following response which fixes my issue. Essentially, even though I have retrieved a Contact that the user selected, I need to do a CNContactFetchRequest to fetch this specific contact again (using the identifier) with keys specified (e.g. organisation).

Here is their exact response: If you want to make sure organizationName is available, execute a CNFetchRequest for a contact with the same identifier (as returned from CNContactPicker delegate method) and provide a set of keys to fetch containing CNContactOrganizationName.

Here is the code:

var validContacts: [CNContact] = []
let contactStore = CNContactStore()
do {
     // Specify the key fields that you want to be fetched.
     // Note: if you didn't specify your specific field request. your app will crash
     let fetchRequest = CNContactFetchRequest(keysToFetch: [CNContactOrganizationNameKey as CNKeyDescriptor])

     fetchRequest.predicate = CNContact.predicateForContacts(withIdentifiers: [contact.identifier])

     try contactStore.enumerateContacts(with: fetchRequest, usingBlock: { (contact, error) -> Void in
          validContacts.append(contact)
     })
     for validContact in validContacts {
          // Do something with your contact, there should be only one.
     }
} catch let e as NSError {
     print(e)
}