0

I have an iOS app which is accessing a core data sql database from two threads. Thread A (the main UI thread) updates a core data record, and Thread B then attempts to read from the Entity collection that Thread A has just updated. Trouble is, Thread B is not 'seeing' the change that Thread A persisted.

Thread B is created by adding an NSOperation subclass object to an NSOperationQueue. The main method of the NSOperation subclass looks like this:

-(void) main {

    // NEED to create the MOC here and pass to the methods.
    NSManagedObjectContext* moc = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSConfinementConcurrencyType];

    [moc setUndoManager:nil];

    [moc setMergePolicy:NSMergeByPropertyStoreTrumpMergePolicy]; // Had been working for months 

    [moc setPersistentStoreCoordinator:getApp().persistentStoreCoordinator];

    [self doTheWorkWithMOC:moc]; // Actually performs updates, using moc


    moc = nil;



}

Later, Thread B saves its changes as follows:

@try {
                // register for the moc save notification - this is so that other MOCs can be told to merge the changes
                [[NSNotificationCenter defaultCenter] 
                 addObserver:getApp() 
                 selector:@selector(handleDidSaveNotification:)
                 name:NSManagedObjectContextDidSaveNotification 
                 object:moc];

                NSError* error = nil;
                if ([moc save:&error] == YES)
                {
                    NSLog(@"%s SAVED FINE",__FUNCTION__);

                }else {
                    NSLog(@"%s NOT saved, error=%@ %@",__FUNCTION__,error,[error localizedDescription]);

                }

                // unregister from notification
                [[NSNotificationCenter defaultCenter] 
                 removeObserver:getApp() 
                 name:NSManagedObjectContextDidSaveNotification 
                 object:moc];





            }
            @catch (NSException * e) {
                NSLog(@"%s Exception: %@",__FUNCTION__, e);

            }

The main UI appdelegate contains the following code to handle the save notification:

- (void)handleDidSaveNotification:(NSNotification*) note 
{

    @try {

        // Notifications run on the same thread as the notification caller.
        // However, we need to ensure that any db merges run on the main ui thread.
        // Hence:
        [self performSelectorOnMainThread:@selector(mergeContexts:) withObject:note waitUntilDone:NO]; 


    }
    @catch (NSException * e) {
        NSLog(@"appDelegate handleDidSaveNotification Exception: %@", e);
    }

}
-(void)mergeContexts:(NSNotification*) note 
{
    if ([__managedObjectContext tryLock]==YES)
    {
        [__managedObjectContext mergeChangesFromContextDidSaveNotification:note];

        [__managedObjectContext unlock];
    }

}

It all works fine most of the time.

However, I have one iPad where the changes written by Thread B are not detected when Thread A reads the database.

Can anyone see anything in my code which would cause this?

Many thanks

Journeyman
  • 10,011
  • 16
  • 81
  • 129

1 Answers1

0

Journeyman,

First, you should move to using the queue based MOCs introduced in iOS v5 and Lion. This will make it much easier to keep your two MOCs in sync. You will no longer need to use the locking system.

Second, once you've moved to the queued MOCs, then it is quite straightforward to keep them in sync in response to the "did save" notifications.

Third, why are you always adding and removing the observer for the did save notifications? Doesn't that look suspicious to you? Clearly, you are missing some update between the MOCs.

Andrew

adonoho
  • 4,339
  • 1
  • 18
  • 22