9

I want get all new added contact Identifier.

Here is my code :

-(void)viewWillAppear:(BOOL)animated {

    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(addressBookDidChange:) name:CNContactStoreDidChangeNotification object:nil];
}

-(void)addressBookDidChange:(NSNotification*)notification
{
    //Handle event here...
    NSDictionary *dict = notification.userInfo;
    NSLog(@"Notification - %@",dict);

}

CNNotificationSaveIdentifiersKey array is always blank.

 Notification - {
    CNNotificationOriginationExternally = 1;
    CNNotificationSaveIdentifiersKey =     (
    );
    CNNotificationSourcesKey =     (
    );
}
Mayuri R Talaviya
  • 613
  • 1
  • 9
  • 14
  • Did you find out, how to get Identifier from the above code? – Nandhakumar Kittusamy Feb 27 '18 at 13:50
  • 1
    I am tried may way but not get success. So at last my solution is when i am get notification that some value is change in contact then i’ll sync my data to server for new contact or any edition. But for this logic your app is either in foreground or in Background. – Mayuri R Talaviya Feb 28 '18 at 09:18
  • how to sync the data to the server. Is there any framework or separate class in iOS for syncing the data with the server? – Nandhakumar Kittusamy Feb 28 '18 at 11:26
  • No there is no framework or class. – Mayuri R Talaviya Feb 28 '18 at 12:26
  • then how did you sync data with the server? can you please put your code as an answer. – Nandhakumar Kittusamy Feb 28 '18 at 13:07
  • Sorry, i can't put full code here , but what i'll do for this 1. At first time take all contact information and upload to server 2. when you get any changes in contact then compare with server data and identify the new update. 3 Now only updated data send to server. You can compare Contact identifier for comparison. – Mayuri R Talaviya Feb 28 '18 at 13:34
  • did you send contacts json array to server or something else. if contact size is large then the request will be failed in low network. – Nandhakumar Kittusamy Feb 28 '18 at 13:50
  • I am used json array. I am not face any contact size issue. – Mayuri R Talaviya Mar 01 '18 at 06:02
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/166015/discussion-between-nandhakumar-and-mayuri-r-talaviya). – Nandhakumar Kittusamy Mar 01 '18 at 06:03
  • I actually get an array with a single string value from userInfo CNNotificationSaveIdentifiersKey. Here's the string value I got: "A5E882D3-CE8B-4B0A-8228-155C76F26E80" I don't know what that matches up with. It looks like maybe it's a UUID value. – daniel Dec 12 '21 at 01:54

2 Answers2

1

iOS 13 added an API for that, but sadly it's only accessible from Objective-C code: enumeratorForChangeHistoryFetchRequest:error:

To use it from Swift, you will need to create a wrapper:

CNContactStore+ChangeHistory.h

#import <Contacts/Contacts.h>

NS_ASSUME_NONNULL_BEGIN
@interface CNContactStore (ChangeHistory)
- (CNFetchResult<NSEnumerator<CNChangeHistoryEvent *> *> *)swiftEnumeratorForChangeHistoryFetchRequest:(CNChangeHistoryFetchRequest *)request
                                                                                                 error:(NSError * _Nullable *)error;
@end

CNContactStore+ChangeHistory.m

#import "CNContactStore+ChangeHistory.h"

@implementation CNContactStore (ChangeHistory)
- (CNFetchResult<NSEnumerator<CNChangeHistoryEvent *> *> *)swiftEnumeratorForChangeHistoryFetchRequest:(CNChangeHistoryFetchRequest *)request
                                                                                                 error:(NSError * _Nullable *)error
{
    return [self enumeratorForChangeHistoryFetchRequest:request error:error];
}
@end

To ensure you only get new changes (and not the complete change history) you will need to save CNContactStore().currentHistoryToken when you get contacts. Then later pass this token in the CNChangeHistoryFetchRequest:

var myToken = myContactStore.currentHistoryToken

// ... then later, after you get CNContactStoreDidChange notification:
let request = CNChangeHistoryFetchRequest()
request.startingToken = myToken
var error: NSError?
let fetchResult = myContactStore.swiftEnumerator(for: fetchRequest, error: &error)
myToken = myContactStore.currentHistoryToken // for next time

for event in fetchResult.value {
    (event as! CNChangeHistoryEvent).accept(myCNChangeHistoryEventVisitor)
    // or alternatively:
    let newContact = (event as? CNChangeHistoryAddContactEvent).contact
}
Yonat
  • 4,382
  • 2
  • 28
  • 37
0

You have to fetch contacts again when you receive this notification. Apple doc says so.

https://developer.apple.com/documentation/contacts/cncontactstore

If you cache the fetched contacts, groups, or containers, you need to refetch these objects (and release the old cached objects) when CNContactStoreDidChange is posted.

infiniteLoop
  • 2,135
  • 1
  • 25
  • 29