Search code examples
ioscore-dataconcurrencypersistencensmanagedobjectcontext

Why aren't my NSManagedObject persisted after a [moc save] PerformBlockAndWait?


Still working on my RSS Reader.

My data model roughly consists of the following NSManagedObject hierarchy:

Category <---->> Feed <---->> Post

My application uses the following:

  • a "root" NSManagedObjectContext with a NSPrivateQueueConcurrencyType Concurrency type. I use this MOC to persist my changes to the NSPersistentStoreCoordinator.

  • a "main" NSManagedObjectContext with a NSMainQueueConcurrencyType Concurrency type. I use this MOC to feed my GUI.

  • "Local" NSManagedObjectContext with a NSPrivateQueueConcurrencyType Concurrency type. I create and use this MOC each time I batch-fetch new Posts objects.

Once the MainViewController is loaded, it populates itself if empty.

At the end of the populatemethod, I make sure everything's properly persisted and also refetch my data:

[_mainMOC performBlockAndWait:^{
    NSError *error;
    if (![_mainMOC save:&error]) {
        NSLog(@"[MainViewController::populate] Error.mainMOC: %@\n%@", [error description], [error userInfo]);

    }
    [[_mainMOC parentContext] performBlockAndWait:^{
        NSError *error;
        if (![[_mainMOC parentContext] save:&error]) {
            NSLog(@"[MainViewController::populate] Error.saveMOC: %@\n%@", [error description], [error userInfo]);

        }
    }];
    NSLog(@"[MainViewController::populate] OK.saveMOC");
}];
NSLog(@"[MainViewController::populate] OK.mainMOC");
[_mainMOC performBlock:^{
    NSError *error;
    if (![_mainMOC executeFetchRequest:[_fetchedResultsController fetchRequest] error:&error]) {
        NSLog(@"[MainViewController::populate] refetch: %@\n%@", [error description], [error userInfo]);

    }
}];

Despite this, I cannot create Posts within my Feeds in a dedicated `localMOC``:

NSManagedObjectID *feedID=[f objectID];
if ([feedID isTemporaryID]) {
    NSLog(@"Warning %@ has not yet been persisted!", f.name);
}
/* ... */
NSManagedObjectContext *localMOC;
localMOC = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
[localMOC setParentContext:self.mainMOC];
/* ... */
[localMOC performBlock:^{
    NSError *error=nil;
    Feed *feed=((Feed *)[localMOC existingObjectWithID:feedID error:&error]);
    if (error) {
        NSLog(@"[MAsterViewController::fetchPosts] %@\n%@", [error localizedDescription], [error userInfo]);
        return;
    }
/* ... */

The above bit of code produces the following log:

2013-11-14 19:24:04.847 uRSS[10907:70b] Warning Maddox has not yet been persisted!
2013-11-14 19:24:04.847 uRSS[10907:1303] [MAsterViewController::fetchPosts] The operation couldn’t be completed. (Cocoa error 133000.)

Could someone tell me what's going wrong here? Thanks!


Solution

  • I finally solved my problems by implementing my own save routine:

    [_localMOC performBlockAndWait:^{
        NSError *errLoc=nil;
    
        if (![self.mainMOC obtainPermanentIDsForObjects:@[[[_mainMOC insertedObjects]     arrayByAddingObjectsFromArray:[_mainMOC updatedObjects]]] error:&errLoc]) {
        NSLog(@" ... ");
        }
    
        if (![_localMOC save:&errLoc]) {
          NSLog(@" ... ");
        }
        [_mainMOC performBlockAndWait:^{
            NSError *errMain=nil;
            if (![_mainMOC save:&errMain]) {
                NSLog(@" ... ");
            }
        }]
    }];
    

    Note that _mainMOC is being observed from the AppDelegate and will have its changes asynchronically persisted to disk by his _saveMOC parent.