Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Restkit [NSManagedObject managedObjectContext] returns different instances

I have serious problems since I migrated my core data logic to RKManagedObjectStore. I setup a NSFetchedResultsController with the context set to [NSManagedObject managedObjectContext] within the main thread in the view controller:

assert([NSThread isMainThread]);
NSManagedObjectContext* context = [NSManagedObject managedObjectContext];
NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:[Item fetchRequest] managedObjectContext:context sectionNameKeyPath:nil cacheName:@"Master"];

I insert objects in the context like this:

Item* item = [Item object];
item.name = @"Foo";
[[RKObjectManager sharedManager].objectStore save];

But the fetched results controller doesn't get notified of the changes. Thus I registered a notification manually:

[[NSNotificationCenter defaultCenter] addObserverForName:NSManagedObjectContextDidSaveNotification object:nil queue:nil usingBlock:^(NSNotification *note) {
    NSLog(@"Context changed");

    [self.fetchedResultsController performFetch:nil];
    [self.tableView reloadData];
}];

This should really not be necessary I think, since RKManagedObjectStore merges changes across different contexts. Second, for deleting the Item object I tried

[item deleteEntity];

This produced an error saying that the object cannot be deleted within another context. This is obviously true, but WHY the hell is the context not the same instance for the Main Thread? I call the following also inside the view controller just before deleting en entity:

assert([NSThread isMainThread]);
NSManagedObjectContext* sameContext1 = [NSManagedObject managedObjectContext];
NSManagedObjectContext* sameContext2 = self.fetchedResultsController.managedObjectContext;
assert(sameContext1 == sameContext2); //FAILS

Looking at RKManagedObjectStore's managedObjectContext getter Implementation which is called when using [NSManagedObject managedObjectContext], the same instance per thread should be returned:

-(NSManagedObjectContext*)managedObjectContext {
    NSMutableDictionary* threadDictionary = [[NSThread currentThread] threadDictionary];
    NSManagedObjectContext* backgroundThreadContext = [threadDictionary objectForKey:RKManagedObjectStoreThreadDictionaryContextKey];
    ...
}
like image 950
Sbhklr Avatar asked Jan 20 '12 12:01

Sbhklr


1 Answers

I finally tracked it down that nasty bug after hours of debugging. The problem is that RKObjectManager holds a reference to RKManagedObjectStore. But somehow when using ARC that reference is not kept in the [RKObjectManager sharedManager] instance and is being deallocated. That causes flushing of the thread local cache. Therefore managed object context merging is not working because on every access a new managed context is created. The fix is easy. Just keep a strong reference to the RKManagedObjectStore in your App Delegate and you're done.

like image 119
Sbhklr Avatar answered Sep 30 '22 19:09

Sbhklr