Get a remote contact using ABAddressBookRegisterExternalChangeCallback or any other notification

Many SO questions have been raised regarding listening to the iOS address book change callback. Famous issue Address Book Sync .

But my question is narrow, i.e. how can we get which contacts were deleted during the address book synchronization callback.

void MyAddressBookExternalChangeCallback (ABAddressBookRef ntificationaddressbook,CFDictionaryRef info,void *context) { NSLog(@"Changed Detected......"); /* NSDate *lastSyncTime = [self gettingLastSyncTime]; // By above time, I could get which contacts are modified(kABPersonModificationDateProperty) // and which contacts are created newly( ABRecordGetRecordID() // But how can I get this contact was DELETED? */ } 

But someone cleared this problem in Found that was changed ..... In this case, they (a) saved all the record identifiers for the first time (b) during synchronization, check all stored record identifiers with the identifiers of the current address book to check whether they are available or not. If not, then suppose it will be a remote contact (expensive operation).

My question is: Is there any other way to detect a DELETED contact?

+5
source share
1 answer

As far as I know, the only way to do this is to save contact IDs in some way and check for changes, because MyAddressBookExternalChangeCallback is called only when your application is active or in the background, so when your application is terminated, it will not be able to track these changes . Here is my implementation of the address book synchronization controller, which simply updates local contacts with devices:

 // Header.h @interface AddressBookSyncController : NSObject + (instancetype)sharedInstance; + (NSString *)archiveFilePath; - (void)syncAddressBook; - (void)beginObserving; - (void)invalidateObserving; @end // Implementation.m NSString *const AddressBookSyncAllKey = @"AddressBookSyncAllKey"; @interface AddressBookSyncController () @property (nonatomic) ABAddressBookRef addressBook; @property (nonatomic) BOOL isObserving; @end @implementation AddressBookSyncController + (instancetype)sharedInstance { static AddressBookSyncController *instance; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ instance = [AddressBookSyncController new]; }); return instance; } + (NSString *)archiveFilePath { // Your archive file path... } - (void)syncAddressBook { dispatch_async(dispatch_get_main_queue(), ^{ if (ABAddressBookGetAuthorizationStatus() != kABAuthorizationStatusAuthorized) return; NSString *archiveFilePath = [AddressBookSyncController archiveFilePath]; BOOL needSyncAllContacts = [[[NSUserDefaults standardUserDefaults] objectForKey:AddressBookSyncAllKey] boolValue]; BOOL archiveExists = [[NSFileManager defaultManager] fileExistsAtPath:archiveFilePath]; if (!needSyncAllContacts && !archiveExists) return; ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, nil); CFArrayRef allPeople = ABAddressBookCopyArrayOfAllPeople(addressBook); NSInteger nPeople = ABAddressBookGetPersonCount(addressBook); NSMutableArray *syncContacts = [NSMutableArray arrayWithCapacity:nPeople]; NSMutableArray *archivedContacts = archiveExists ? [[NSKeyedUnarchiver unarchiveObjectWithFile:archiveFilePath] mutableCopy] : [NSMutableArray array]; if (needSyncAllContacts) { NSMutableArray *newContacts = [NSMutableArray array]; for (NSInteger i = 0; i < nPeople; ++i) { ABRecordRef record = CFArrayGetValueAtIndex(allPeople, i); NSInteger recordId = ABRecordGetRecordID(record); NSDate *modificationDate = (__bridge_transfer NSDate *)ABRecordCopyValue(record, kABPersonModificationDateProperty); AddressContact *contact = [[archivedContacts filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"recordId == %i", recordId]] firstObject]; if (contact && [contact.modificationDate isEqualToDate:modificationDate]) continue; AddressContact *newContact = [AddressContact addressContactWithRecord:record]; [syncContacts addObject:newContact]; if (contact) { NSUInteger idx = [archivedContacts indexOfObject:contact]; if (idx != NSNotFound) { [archivedContacts replaceObjectAtIndex:idx withObject:newContact]; } else { NSLog(nil, @"idx == NSNotFound for syncAddressBook"); } } else { [newContacts addObject:newContact]; } } [archivedContacts addObjectsFromArray:newContacts]; } else { for (NSInteger i = 0, l = archivedContacts.count; i < l; ++i) { AddressContact *contact = [archivedContacts objectAtIndex:i]; ABRecordRef record = ABAddressBookGetPersonWithRecordID(addressBook, (int)contact.recordId); if (!record) continue; NSDate *modificationDate = (__bridge_transfer NSDate *)ABRecordCopyValue(record, kABPersonModificationDateProperty); if ([modificationDate isEqualToDate:contact.modificationDate]) continue; AddressContact *newContact = [AddressContact addressContactWithRecord:record]; [syncContacts addObject:newContact]; [archivedContacts replaceObjectAtIndex:i withObject:newContact]; } } CFRelease(allPeople); CFRelease(addressBook); BOOL result = NO; if ([syncContacts count] != 0) { // Do your logic with contacts result = [NSKeyedArchiver archiveRootObject:archivedContacts toFile:archiveFilePath]; } NSLog(@"Archiving %@", result ? @"Succeed" : @"Failed"); [[NSUserDefaults standardUserDefaults] setObject:@(NO) forKey:AddressBookSyncAllKey]; [[NSUserDefaults standardUserDefaults] synchronize]; }); } - (void)beginObserving { if (self.isObserving || ABAddressBookGetAuthorizationStatus() != kABAuthorizationStatusAuthorized) return; self.addressBook = ABAddressBookCreateWithOptions(NULL, nil); ABAddressBookRegisterExternalChangeCallback(self.addressBook, addressBookChanged, (__bridge void *)self); self.isObserving = YES; } - (void)invalidateObserving { if (!self.isObserving) return; ABAddressBookUnregisterExternalChangeCallback(self.addressBook, addressBookChanged, (__bridge void *)self); CFRelease(self.addressBook); self.isObserving = NO; } void addressBookChanged(ABAddressBookRef reference, CFDictionaryRef dictionary, void *context) { NSLog(@"%@ changed %@", reference, dictionary); ABAddressBookRevert(reference); [(__bridge AddressBookSyncController *)context syncAddressBook]; } @end 
+1
source

All Articles