Since I switched to Mac OS Sierra and XCode 8, code that was using unifiedContactsMatchingPredicate:keysToFetch:error: or unifiedContactWithIdentifier:keysToFetch:error: no longer run correctly.
An error is returned : Error domain: CNErrorDomain code: 200 With a description saying the record does not exist, or the update of the record failed.
All codes were working fine with Mac OS 10.11 and XCode 7, read access to address book are granted and the CNContact I am looking for does exist.
I had the same behavior with iOS 10, which I solved by adding a NSContactsUsageDescription key in the plist file (that was optional before iOS 10, but no longer). I did the same in my mac OS plist file with no luck.
Any clue what's going on and where to search ?
EDIT : with some code :
I wrote 2 new projects, one in Objective-C, one in Swift. Both of them give the same result.
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
// Insert code here to initialize your application
CNContactStore *contactStore = [[CNContactStore alloc] init] ;
NSPredicate *predicate = [CNContact predicateForContactsMatchingName:@"TEST_CONTACT"] ;
NSError *error = nil ;
NSArray *keys = @[
CNContactGivenNameKey,
CNContactFamilyNameKey
] ;
NSArray *contacts = [contactStore unifiedContactsMatchingPredicate:predicate
keysToFetch:keys
error:&error] ;
NSLog(@"%d contacts found : %@",[contacts count],contacts) ;
}
and
func applicationDidFinishLaunching(_ aNotification: Notification) {
// Insert code here to initialize your application
let contactStore = CNContactStore()
let predicate = CNContact.predicateForContacts(matchingName: "TEST_CONTACT")
let keys = [CNContactGivenNameKey,CNContactFamilyNameKey]
do
{
let contacts = try contactStore.unifiedContacts(matching: predicate,
keysToFetch: keys as [CNKeyDescriptor])
print(contacts)
}
catch
{
print("caught an error")
}
}
Result shown in the console :
2016-09-27 17:19:48.797029 TestCNContact.swift[13675:3502046] [core] __42-[ACAccountStore accountsWithAccountType:]_block_invoke_2 (208) "Error returned from daemon: <private>"
2016-09-27 17:19:48.798105 TestCNContact.swift[13675:3502046] [core] __42-[ACAccountStore accountsWithAccountType:]_block_invoke_2 (208) "Error returned from daemon: " [] 2016-09-27 17:19:49.631876 TestCNContact.swift[13675:3502047] [error] warning: dynamic accessors failed to find @property implementation for 'uniqueId' for entity ABCDInfo while resolving selector 'uniqueId' on class 'ABCDInfo'. Did you remember to declare it @dynamic or @synthesized in the @implementation ? 2016-09-27 17:19:52.637627 TestCNContact.swift[13675:3502047] [error] warning: dynamic accessors failed to find @property implementation for 'serialNumber' for entity ABCDAddressBookSource while resolving selector 'serialNumber' on class 'ABCDAddressBookSource'. Did you remember to declare it @dynamic or @synthesized in the @implementation ? 2016-09-27 17:19:52.739108 TestCNContact.swift[13675:3502068] [error] warning: dynamic accessors failed to find @property implementation for 'uniqueId' for entity ABCDAddressBookSource while resolving selector 'uniqueId' on class 'ABCDAddressBookSource'. Did you remember to declare it @dynamic or @synthesized in the @implementation ?
I found a solution !!!
Apple has answered my radar with the following statement : "Contacts now requires that anyone using it be codesigned with the uses-contacts entitlement."
So what I did is that I sandboxed my app, and granted the "Contacts access" entitlement. Everything works fine again.
It seems Apple will no longer accept non sandboxed app to access the Contacts (or location or calendar).