Ios 使用ABAddressBookRegisterExternalChangeCallback或任何其他通知获取已删除的联系人

Ios 使用ABAddressBookRegisterExternalChangeCallback或任何其他通知获取已删除的联系人,ios,objective-c,addressbook,abaddressbook,abaddressbooksource,Ios,Objective C,Addressbook,Abaddressbook,Abaddressbooksource,很多问题都是关于如何收听iOS地址簿更改回调的。著名的问题 但我的问题很狭隘,也就是说,我们如何获取在通讯录同步回调期间删除的联系人 void MyAddressBookExternalChangeCallback (ABAddressBookRef ntificationaddressbook,CFDictionaryRef info,void *context) { NSLog(@"Changed Detected......"); /* NSDate *lastSyncTime

很多问题都是关于如何收听iOS地址簿更改回调的。著名的问题

但我的问题很狭隘,也就是说,我们如何获取在通讯录同步回调期间删除的联系人

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?
 */
}
但是有人把这个问题解决了。在这种情况下,他们做到了(a)第一次存储所有记录ID(b)在同步期间,检查所有存储的记录ID与当前通讯簿ID,以检查它们是否可用。如果没有,则假定它已被删除(代价高昂的操作)


我的问题:还有其他方法检测已删除的联系人吗?

据我所知,唯一的方法是以某种方式存储联系人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
//Header.h
@接口地址BookSyncController:NSObject
+(instancetype)sharedInstance;
+(NSString*)存档文件路径;
-(作废)同步通讯录;
-(无效)开始观察服务;
-(无效)无效观察服务;
@结束
//实施.m
NSString*const AddressBookSyncAllKey=@“AddressBookSyncAllKey”;
@接口地址BookSyncController()
@属性(非原子)ABAddressBookRef addressBook;
@性质(非原子)布尔;
@结束
@实现地址BookSyncController
+(instancetype)sharedInstance
{
静态AddressBookSyncController*实例;
静态调度一次;
一次发送(一次发送)^{
实例=[AddressBookSyncController新建];
});
返回实例;
}
+(NSString*)存档文件路径
{
//您的存档文件路径。。。
}
-(作废)同步通讯录
{
dispatch\u async(dispatch\u get\u main\u queue()^{
if(ABAddressBookGetAuthorizationStatus()!=kABAuthorizationStatusAuthorized)返回;
NSString*archiveFilePath=[AddressBookSyncController archiveFilePath];
BOOL needSyncAllContacts=[[NSUserDefaults standardUserDefaults]objectForKey:AddressBookSyncCallKey]boolValue];
BOOL archiveExists=[[NSFileManager defaultManager]fileExistsAtPath:archiveFilePath];
如果(!needSyncAllContacts&&!archiveExists)返回;
ABAddressBookRef addressBook=ABAddressBookCreateWithOptions(NULL,nil);
CFArrayRef allPeople=abAddressBookCopyArrayFallPeople(addressBook);
NSInteger nppeople=ABAddressBookGetPersonCount(地址簿);
NSMutableArray*syncContacts=[NSMutableArray阵列容量:NPEOPE];
NSMutableArray*archivedContacts=archiveExists?[[NSKeyedUnarchiveObjectWithFile:archiveFilePath]mutableCopy]:[NSMutableArray];
如果(需要同步所有联系人)
{
NSMutableArray*新联系人=[NSMutableArray];
对于(NSInteger i=0;i