CNContactStoreDidChangeNotification is fired multiple times
Asked Answered
G

3

28

I am able to observe the CNContactStoreDidChangeNotification when the contact database is changed while the app is in background state. I am pretty sure that only one observer was added to NSNotificationCenter. The problem is NSNotificationCenter posts MULTIPLE times (2, 3, 5, and even more times) even if I only add one new contact. Where is the problem?

Gomar answered 1/1, 2016 at 22:16 Comment(4)
Any updates on this?Leilanileininger
I also have this issue. Even in the best case, adding a contact generates at least 2 CNContactStoreDidChangeNotification notifications. However, my notifications only occur when I return back to my app, but not while in the background. Anyone else has this issue.Elmaelmajian
I had a similar issue with applicationDidBecomeActive on iPhone running iOS 10, only in landscape mode. Please see : #39622892 I opened a new bug in the Apple Bug Reporter. Apple asked me for more details, I sent them my complete Xcode project... but I had no solution. The bug is still open...Unbated
I don't think there is a problem. If you look at the userInfo dictionary in a notification fired from the older kABDatabaseChangedExternallyNotification, you'll see that the notification is actually fired from one or more ABSenderProcessNames, like Contacts.app and AddressBookSourceSync. If you try updating a contact from your phone, you will get one notification from AddressBookSourceSync.Pyatt
C
4

Make certain you aren't adding the observer multiple times. This can happen without you realizing it if (for example) you call -addObserver from -viewDidLoad or -viewDidAppear in your view controller (as these might get called more than once throughout the life of your application), or from any of the application state callbacks in your app delegate (-applicationDidBecomeActive, -applicationWillResignActive, -applicationDidEnterBackground, -applicationWillEnterForeground, etc).

Wrap the call to -addObserver in a conditional that ensures it can only be called once (set a flag), and put NSLog statements around it so you can see in the debug console if you are getting there more than once. Search your code for other calls to -addObserver that you might have forgotten about.

Call -removeObserver before adding it, just to be sure (making sure to pass the same name and object as when you added it). Calling -removeObserver on an observer that doesn't exist is okay. Note that this is more of a band-aid than a fix - your code should be smart enough to know whether or not you've already added it - but this might help you diagnose the problem).

I just wrote a quick minimal test program that adds an observer (once!) on CNContactStoreDidChangeNotification and I only get the notification once when I add or change a contact. Write a similar test program for yourself and see if you get the same result. If your test program works correctly, then it is likely that your app is doing something you don't expect (and calling -addObserver multiple times).

Coed answered 26/4, 2017 at 17:56 Comment(2)
Did you try it on big contact data (like I'm testing on the 500+ contacts)? I double-checked that the observer is registered only once (it's single-tone, and in debugger you can really follow it). Nevertheless, I get 3 echoes for every contact change. My solution was to make processing of changes in background, and I turn thread to sleep for 3 secs before processing, and cancelling the operation if there is a new update. Thus I ensure only latest from the "echo" will be processed. BTW, in older iOSs I set to 2 secs sleep, now with 10.3.3 I set it to 3 secs (as echos coming later now)Roselynroseman
Jeff's observation is very good and to the point. That's the easiest mistake one could possible do, to add the observer multiple times. But the problem is real and it's not due to multiple calls to addObserver. Nick's solution may work, but sleep should be avoided. Instead one could use a timer or dispatch_after to do the trick.Palpebrate
C
0

I had the same problem, the number of times it fired varied between 2 & 3. The solution that worked for me was to set a semaphore variable, set in the handler and reset the semaphore when finished. Wrap the address book processing in an if statement on the semaphore to ignore further calls. addressBkSemphore is reset to false in buildFrendsAndContacts

- (void)addressBkChange:(NSNotification *)note
{   
    if (addressBkSemphore == false)
    {
        addressBkSemphore = TRUE;
        [self buildFrendsAndContacts];
    }
}

Hope it helps.

Contemptuous answered 12/7, 2017 at 9:30 Comment(1)
The solution others proposed, of pausing before processing the change, seems like it may be better as it means the latest version of your address book is used (in the event that two changes happen close together- say if someone made a few edits on another device whilst offline, then connected to wifi)Finite
P
0

You can start a one time execution timer or a dispatch after few seconds and cancel it in case there's a new contacts update within those seconds, thus ensuring that only the timer or dispatch_after triggered by the last update will actually execute (taking into account that all update calls come one after the other within under a sec. difference, as far as I tested)

And btw, I could reproduce the issue only when making change to contacts on the same device with my app. If I change the contacts on another device linked to the same apple account, there was only one update.

Palpebrate answered 13/1, 2018 at 19:13 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.