2012-04-10 47 views
9

我有一个奇怪的问题,我注册我的iOS应用程序来监听电话地址簿中的更改。当地址簿中的内容发生变化时调用正确的方法,但它会被调用2-6次。ABAddressBookRegisterExternalChangeCallback多次调用

当对象被创建(单,所以只有一个对象),I注册与此代码通知:

ABAddressBookRegisterExternalChangeCallback(notificationAddressBook, addressBookChanged, (__bridge_retained void *)self); 

的方法,被称为如下所示:

void addressBookChanged(ABAddressBookRef ab, CFDictionaryRef info, void *context){ 
ABAddressBookRevert(ab); 

    NSLog(@"ADDRESSBOOK CHANGED"); 
    [phoneBookCopy updateCopy]; 
} 

不限想法如何解决这个问题?

+2

我也有这个问题。每当我切换到iOS通讯录以更改联系人的姓名并切换回我的应用程序时,回调都会被调用四次 - 始终如此。我在注册时尝试添加上下文,并且看到我的上下文在四次调用中都发送给我。 我在这里阅读:http://stackoverflow.com/questions/7116956/gcd-and-callbacks-concurrency-issue有人声称这是一个已知的错误,但我还没有找到它。有人有关于这种刺激性行为的更多信息吗? – 2012-05-16 11:45:19

回答

1

我有同样的问题前一段时间,我不得不通过创建的NSTimer来处理重复的回调,以解决这个问题:

[self.changeTimer invalidate]; 
self.changeTimer = nil; 
self.changeTimer = [NSTimer scheduledTimerWithTimeInterval:3.0 
                  target:self 
                  selector:@selector(handleAdressBookExternalCallbackBackground) 
                  userInfo:nil 
                  repeats:NO]; 
+0

我想你是多次调用方法:ABAddressBookRegisterExternalChangeCallback。 – 2012-11-06 13:00:34

+0

对不起,@Z S,我发现我错了,你是对的,对不起,对这个答案下来投票! – flypig 2012-11-21 07:38:28

+0

只需稍作改进,ZS代码将在计时器到期后才运行处理程序,您可以检查changeTimer是否为零,如果处理通知并启动计时器。计时器应该调用一个设置changeTimer = nil的选择器,所以我们将在超时过期后处理下一个通知 – marmor 2013-01-06 16:48:57

0

我有一个类似的问题。回调只会在第一次被调用,但如果我第二次出去更改地址簿,那么它将被多次调用。 对我而言,问题在于在AppDelegate的applicationWillResignActive:方法中调用ABAddressBookRegisterExternalChangeCallback的方法。

我使用地址簿的方式是用于同步设置。问题是,每次同步设置为保存,而不是仅当同步设置为时更改为,我才注册外部回调。

为了说明,这里是我打电话在的appDelegate

- (void)saveSettings 
{ 
NSUserDefaults *syncSettingsData = [NSUserDefaults standardUserDefaults]; 
[syncSettingsData setObject:[NSNumber numberWithBool:self.isSyncingiPadContacts] forKey:SYNC_IPAD_CONTACTS_TURNED_ON]; 
[self setAddressBookChanged]; 
[syncSettingsData synchronize]; 
} 

- (void)setAddressBookChanged 
{ 
    if (self.isSyncingiPadContacts) 
    { 
     ABAddressBookRegisterExternalChangeCallback(self.addressBook, addressBookChanged, (__bridge void *)self); 
    } 
    else 
    { 
     ABAddressBookUnregisterExternalChangeCallback(self.addressBook, addressBookChanged, (__bridge void *) self); 
    } 
} 

我在saveSettings方法去除调用setAddressBookChanged代码,并开了叫时正在创建的地址簿(首次设立)和每当用户更改同步设置。

希望这可以帮助你。

0

我的解决方案很简单,它不仅适用于此,而且适用于所有重复回调(包括本地通知重复调用): 我使用最后一次调用时间保留属性并检查时间间隔。 希望它有帮助,对我来说它做到了这一点。

AppDelegate * delegate =(__bridge AppDelegate *)context;

if (delegate.lastCall==nil) { 
    delegate.lastCall = [[NSDate alloc]init]; 
} 
else { 
    NSTimeInterval interval = [[NSDate date] timeIntervalSinceDate:delegate.lastCall]; 
    if (interval<20) { 
     return; 
    } 
    else { 
     delegate.lastCall = [[NSDate alloc]init]; 
    } 
} 
+0

好逻辑,但是这起作用或不起作用,以避免在谷歌背景中同步多个联系人? – 2015-07-29 09:08:40

3

试试这个:

void addressBookChanged(ABAddressBookRef ab, CFDictionaryRef info, void *context){ 
ABAddressBookRevert(ab); 

    NSLog(@"ADDRESSBOOK CHANGED"); 
    [phoneBookCopy updateCopy]; 
    CFRelease(ab); 
} 

有人帮我。