ABAddressBookRegisterExternalChangeCallback вызывается несколько раз

У меня странная проблема, когда я регистрирую свое iOS-приложение для прослушивания изменений в адресной книге телефона. Правильный метод вызывается, когда что-то меняется в адресной книге, но вызывается от 2 до 6 раз.

Когда объект создается (одиночный, поэтому только один объект), я регистрируюсь для уведомлений с помощью этого кода:

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

Вызываемый метод выглядит следующим образом:

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

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

Есть идеи, как это решить?


person joakimb    schedule 10.04.2012    source источник
comment
У меня тоже есть эта проблема. Каждый раз, когда я переключаюсь на адресную книгу iOS, чтобы изменить имя контакта и вернуться к моему приложению, обратный вызов вызывается четыре раза — всегда. Я попытался добавить контекст при регистрации и вижу, что мой контекст отправляется мне во всех четырех вызовах. Я прочитал здесь: stackoverflow.com/questions/7116956/ что кто-то утверждает, что это известный баг, но я его не нашел. Есть ли у кого-нибудь больше информации об этом раздражающем поведении?   -  person Ricky Helgesson    schedule 16.05.2012


Ответы (4)


попробуй это:

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

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

Мне помогло.

person rusBogun    schedule 03.06.2014

У меня была такая же проблема некоторое время назад, и мне пришлось решить ее, создав NSTimer для обработки повторяющихся обратных вызовов:

[self.changeTimer invalidate];
self.changeTimer = nil;
self.changeTimer = [NSTimer scheduledTimerWithTimeInterval:3.0
                                                            target:self
                                                          selector:@selector(handleAdressBookExternalCallbackBackground)
                                                          userInfo:nil
                                                           repeats:NO];
person Z S    schedule 16.05.2012
comment
Я думаю, вы вызываете метод: ABAddressBookRegisterExternalChangeCallback несколько раз. - person Zain Raza; 06.11.2012
comment
Извините, @Z S, я обнаружил, что ошибался в этом, вы правы, извините за то, что проголосовали против этого ответа !!!! - person flypig; 21.11.2012
comment
Небольшое улучшение, код ZS будет запускать обработчик только после истечения времени таймера, вы можете проверить, является ли changeTimer нулевым, обрабатывает ли он уведомление и запускает таймер. Таймер должен вызывать селектор, который устанавливает changeTimer = nil, поэтому мы обработаем следующее уведомление после истечения времени ожидания. - person marmor; 06.01.2013

У меня была аналогичная проблема. Обратный вызов будет вызван только один раз в первый раз, но если я выйду и внесу изменения в адресную книгу во второй раз, он будет вызван несколько раз. Для меня проблема заключалась в том, что метод, который содержал ABAddressBookRegisterExternalChangeCallback, вызывался в методе appDelegate applicationWillResignActive:.

Адресную книгу я использовал для настройки синхронизации. Проблема заключалась в том, что я регистрировал внешний обратный вызов каждый раз, когда настройки синхронизации сохранялись, а не только тогда, когда настройки синхронизации менялись.

Чтобы проиллюстрировать, вот код, который я вызывал в 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);
    }
}

Я удалил вызов setAddressBookChanged в методе saveSettings, и он просто вызывался при создании адресной книги (первая настройка) и всякий раз, когда пользователь менял настройки синхронизации.

Надеюсь, это поможет вам.

person plasmaTonic    schedule 22.10.2013

Мое решение было довольно простым, и оно работает не только для этого, но и для всех повторных обратных вызовов (включая повторные вызовы локальных уведомлений): я сохраняю свойство со временем последнего вызова и проверяю временной интервал. Надеюсь, это поможет, для меня это сделало работу.

Делегат AppDelegate* = (__bridge AppDelegate*)контекст;

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];
    }
}
person Eran Katsav    schedule 17.11.2013
comment
хорошая логика, но это работает или нет в случае синхронизации нескольких контактов в фоновом режиме из Google? - person Lalit Kumar; 29.07.2015