0

I have a situation where I make some changes to the properties of a NSManagedObject in main thread. It belongs to the main ManagedObjectContext of the app.

My app does has threading enabled which downloads data, each thread has it's own ManagedObjectContext created from the most recent state of a single PersistentStore throughout the application.

I am implementing NSManagedObjectContextDidSaveNotification so that any changes in the MOC is merged back to the main thread's MOC too. Below is the code for it:

- (void)backgroundMOCDidSave:(NSNotification*)notification
{
    // Probable fix for: http://stackoverflow.com/questions/3446983/collection-was-mutated-while-being-enumerated-on-executefetchrequest
    if (![NSThread isMainThread])
    {
        [self performSelectorOnMainThread:@selector(backgroundMOCDidSave:) withObject:notification waitUntilDone:YES];
        return;
    }

    // We merge the background moc changes in the main moc
    [self.managedObjectContext mergeChangesFromContextDidSaveNotification:notification];
}

Registering for this notification:

        [[NSNotificationCenter defaultCenter] addObserver:self
                                                 selector:@selector(backgroundMOCDidSave:)
                                                     name:NSManagedObjectContextDidSaveNotification
                                                   object:nil];

Strange things happen in iOS 7 though. I am accessing a NSManagedObject which is created from the main MOC:

  • When I modify a property of the ManagedObject which belongs to main MOC (main thread) and perform a -save the -backgroundMOCDidSave: call is not triggered
  • When I do not modify any property of the ManagedObject and just perform a -save operation on its MOC the notification is triggered

The same code is working perfectly well in iOS 6. Irrespective of whether any changes is done on the ManagedObject or not, when a -save call is triggered on it's MOC the notification NSManagedObjectContextDidSaveNotification gets triggered.

Anyone faced this problem before?

Raj Pawan Gumdal
  • 7,390
  • 10
  • 60
  • 92

1 Answers1

1

For now I've noticed one thing that's wrong, but I'm not sure it's causing your error. NSManagedObjectContextDidSaveNotification is sent on the thread on which MOC that calls save is running. But merging should be made on the thread MOC merging changes is running on. In your case it works fine if changes are merged from the background to the main MOC, but not the other way around.

Arek Holko
  • 8,966
  • 4
  • 28
  • 46
  • Yes, what you have mentioned is just an assertion of my point. Is something wrong in the implementation here? The DidSave notification should have been triggered on main MOC as it will be (has been) written to the persistent store, isn't it? – Raj Pawan Gumdal Oct 07 '13 at 09:18
  • I've looked closer and I see that your implementation doesn't handle merging changes from the main to the background MOC. You need another method, such as `mainMOCDidSave`. Then you have to change your subscription to notifications to depend on the context. Instead of `object:nil];` you should have two subscriptions: `object:self.managedObjectContext];` and `object:self.backgroundManagedObjectContext];` – Arek Holko Oct 07 '13 at 09:38
  • Ok, I understand your point now. Apart from the main MOC in main thread, I create MOCs for each thread. So, the threads MOC does not live long. When I get all data from the server, I make sure that I call -save on main MOC only after that I create the MOC for thread, this makes sure that the MOC for the thread is created from the most updated state of persistent store. But the problem for me is not in the secondary threads and it's MOCs. Rather here, the changes done to the ManagedObject of the main MOC is not triggering NSManagedObjectContextDidSaveNotification when I perform -save operation. – Raj Pawan Gumdal Oct 07 '13 at 09:44
  • 1
    Yeah, I'm not sure why that's happening. Do you check for errors while saving the main MOC? – Arek Holko Oct 07 '13 at 09:57
  • Thank you, I missed checking the save error. It is giving up NSMergeConflict. However, this leads me to another issue which some other guy has already posted in SO: http://stackoverflow.com/questions/19178972/nsmergeconflict-on-ios7 But this can be marked as resolved, thank you. – Raj Pawan Gumdal Oct 07 '13 at 10:37