关于收听iOS地址簿更改回调,提出了许多SO问题。着名问题Address book sync。
但我的问题很狭窄,即如何在地址簿同步回调期间删除哪些联系人被删除。
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?
*/
}
但是有人在Detect what was changed....中清除了这个问题。在这里,他们做了(a)第一次存储所有记录ID(b)在同步期间,检查所有存储的记录ID与当前地址簿ID,以检查它们是否可用。如果没有,则假设它被删除联系(代价高昂的操作)。
我的问题:还有其他方法可以检测DELETED联系人吗?
答案 0 :(得分:1)
据我所知,唯一的方法是以某种方式存储联系人ID并检查已修改,因为MyAddressBookExternalChangeCallback
仅在您的应用处于活动状态或后台时调用,因此当您的应用是终止,您将无法跟踪这些更改。这是我的地址簿同步控制器的实现,它只是与设备保持最新的本地联系人:
// 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