6

I'm trying to remove redundancy of URLs to my application. This works well, if a single contact has several URLs. But if there are linked contacts, typically save operation fails with the message "The operation couldn’t be completed. (CNErrorDomain error 2.)"

Any advice how to work around this? Doesn't it work with unified contact? If remove of an URL should happen separately on individual non-unified items, is there a way to get those from unified one?

Here is excerpt of the code:

CNSaveRequest *saveRequest = [[CNSaveRequest alloc] init];

NSArray* keys = @[CNContactUrlAddressesKey];
NSPredicate *predicate = [CNContact predicateForContactsWithIdentifiers:identifiers];
NSError *error;
NSArray <CNContact *> *contacts = [_contactStore unifiedContactsMatchingPredicate:predicate keysToFetch:keys error:&error];

for (CNContact *contact in contacts) {
 // here we'll collect non-ambigous URLs
  NSMutableArray<CNLabeledValue<NSString *> *> *copyOfURLs = [NSMutableArray array];
 // just a marker for the moment if a URL with specific prefix was already found
  NSString *baseURL = nil;
  for (CNLabeledValue<NSString *> *labeledValue in contact.urlAddresses) {
    NSString *url = labeledValue.value;
    if ([url hasPrefix:APP_IDENTITY_URL_SCHEME]) {
       if (baseURL == nil)
         baseURL = url;
       else
         continue;
     }
     [copyOfURLs addObject:labeledValue];
  }
  CNMutableContact *updatedContact = [contact mutableCopy];
  updatedContact.urlAddresses = copyOfURLs;
  [saveRequest updateContact:updatedContact];
}
NSError *saveError;
if (![_contactStore executeSaveRequest:saveRequest error:&saveError]) {
  NSLog(@"Saving error: %@", saveError.localizedDescription);
}
bneely
  • 9,083
  • 4
  • 38
  • 46
Nick Entin
  • 1,087
  • 8
  • 18

1 Answers1

0

I understand this is too late to answer, but I faced the same issue i.e. CNContactStore executeSaveRequest failing with (CNErrorDomain error 2.) and came across this unanswered question. I solved my issue which was same, I was setting imageData with zero byte array.

I found the root cause of this issue. If your array above does not have any values i.e. 0 element array, then this line causes the issue.

updatedContact.urlAddresses = copyOfURLs;

If you don't have any element in copyOfURLs, don't even set the updatedContact.urlAddresses with empty (0 element) array.

Replace above line with

if ([copyOfURLs length] > 0) {
  updatedContact.urlAddresses = copyOfURLs;
}
Jay
  • 186
  • 2
  • 18
  • Thanks, @Jay, i'll give it a try. Actually my first attempts were really on the data with redundant URLs, therefore there should not be empty arrays, but it was long ago and may be really there was a case and I need to doublecheck. As you see in the comments - the issue was still unanswered until end of Apr'20. So your help is appreciated! – Nick Entin Jul 24 '20 at 09:15
  • Not sure i got what the problem is, could you please clarify? I use a package doing the following: 1) It clears contact.urlAddresses = [], and then adds 2) (args["websites"] as! [[String: Any]]).forEach { Website(fromMap: $0).addTo(contact) } But i am having CnErrorDomain 2 and Violated constraints error for only 5% of users, any help would be appreciated :) @Jay – Yassin Sameh Feb 06 '23 at 14:57