Search code examples
ioscore-dataios9

NSManagedObjectContextDidSaveNotification called multiple times


Hi I have a FriendsViewController where I display my friends records fetched from coreData. I have another View Controller AddFriendViewController Which is presented by FriendsViewController to add a new friend the and it saves the the Context in it. I am listening to this notification of changes on the shared MOC in my FriendsViewController.

 [[NSNotificationCenter defaultCenter]
 addObserverForName:NSManagedObjectContextDidSaveNotification
 object:appdelegate.context queue:nil 
 usingBlock:^(NSNotification * _Nonnull note) {
                    NSLog(@"Re-Fetch Whole Friends Array from core data and Sort it with UILocalizedIndexedCollation and  reloadData into table");
                }];

In AddFriendsViewController just create a friend object and i

Friend *friend= [NSEntityDescription 
                insertNewObjectForEntityForName:@"Friend" 
                inManagedObjectContext:appdelegate.context];
friend.name=nameTextfield.text;
[appdelegate.context save:&error];
[self.navigationController popViewControllerAnimated:YES];

Now when I perform save on the context from a AddFriendViewController the above block in FriendsViewController is triggered couple of times instead of one time which cause more processing because re-fetching whole data from core data.I cannot use Fetched Results Controller because I am using UILocalizedIndexedCollation to sort my array into section. So my question is why it is being called twice or sometimes even thrice? Or is there any alternative for this ?


Solution

  • Only you know when you want the notification observer to be active.

    However, two common paradigms are:

    If you want to be notified anytime during the life of the view controller, then you register the observer in viewDidLoad and remove the observer in dealloc.

    If you want to be notified anytime the view is active, you register the observer in viewWillAppear and remove in viewWillDisappear.

    EDIT

    I used this statement to remove all entries [[NSNotificationCenter defaultCenter]removeObserver:self]; And it was still showing same behaviour. Then I used addObserver: selector: name: object: method which worked. But Why the other one was not removed ? – Asadullah Ali

    That's because you added a block-based observer, which returns an observer object. You remove the object it returned to you. You really should read the documentation of each method that you use.

    If you use the block-observer method, the add/remove will look like this.

    id observer = [[NSNotificationCenter defaultCenter]
        addObserverForName:SomeNotification
                    object:objectBeingObserved
                     queue:nil
                usingBlock:^(NSNotification *note) {
        // Do something
    }];
    
    [[NSNotificationCenter defaultCenter] removeObserver:observer];
    

    If you use the selector-observer method, you need to remove the observer that you provide to the add call.

    [[NSNotificationCenter defaultCenter]
        addObserver:someObject
           selector:@selector(notificationHandler:)
               name:SomeNotification
             object:objectBeingObserved];
    
    [[NSNotificationCenter defaultCenter]
        removeObserver:someObject
                  name:SomeNotification
                object:objectBeingObserved];