Using RestKit, I am mapping then saving objects from JSON in a background thread with a dedicated context.
I believe I am facing the problem highlighted here: NSFetchedResultsController with predicate ignores changes merged from different NSManagedObjectContext It is also very well explained here: http://www.mlsite.net/blog/?p=518
But my issue is not with UPDATED objects, but INSERTED ones. In my main MOC, I can see that the objects have been inserted after mergeChangesFromContextDidSaveNotification
, but their data is at fault. I guess that's the reason why the NSPredicate
on my NSFetchedResultController
does not work (it looks at a specific field).
I tried the workaround from the other SO question but I could not get it to work.
[[NSNotificationCenter defaultCenter]
addObserverForName:NSManagedObjectContextObjectsDidChangeNotification
object:nil
queue:nil
usingBlock:^(NSNotification* note)
{
NSManagedObjectContext *moc = managedObjectStore.mainQueueManagedObjectContext;
if (note.object != moc){
// When I look at note.userInfo.description, I can see that the objects seem properly created and inserted, with all their data
[moc performBlock:^(){
[moc mergeChangesFromContextDidSaveNotification:note];
}];
}
else {
// This does get called, i.e. the main moc is indeed saved properly. BUT when I look at note.userInfo.description the objects' data is at fault. And my NSFetchedResultController does not pick up the insertion.
}
}
];
UPDATE: adding my FRC config:
- (NSFetchedResultsController *)fetchedResultsController {
if (_fetchedResultsController != nil) {
return _fetchedResultsController;
}
NSFetchedResultsController* theFetchedResultsController;
NSFetchRequest* fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"User"];
fetchRequest.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"userID" ascending:YES]];
theFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:nil cacheName:nil];
// Note: self.managedObjectContext is set to [RKManagedObjectStore defaultStore].mainQueueManagedObjectContext
self.fetchedResultsController = theFetchedResultsController;
_fetchedResultsController.delegate = self;
[_fetchedResultsController performFetch:NULL];
return _fetchedResultsController;
}
UPDATE 2: here is what I do when I receive JSON data:
RKObjectManager *manager = [RKObjectManager sharedManager];
NSPredicate *pre = [NSPredicate predicateWithFormat:@"keyPath IN %@", @"users"];
RKEntityMapping *mapping = (RKEntityMapping *)[[[manager responseDescriptors] filteredArrayUsingPredicate:pre].firstObject mapping];
NSDictionary *mappingsDictionary = @{ [NSNull null]: mapping };
if (!_backgroundMOC){ // Create a MOC for background mapping
NSManagedObjectContext* context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
context.persistentStoreCoordinator = [RKManagedObjectStore defaultStore].persistentStoreCoordinator;
_backgroundMOC = context;
}
RKManagedObjectStore *store = [RKManagedObjectStore defaultStore];
RKManagedObjectMappingOperationDataSource *mappingDataSource = [[RKManagedObjectMappingOperationDataSource alloc] initWithManagedObjectContext:_backgroundMOC cache:store.managedObjectCache];
RKMapperOperation *mapperOperation = [[RKMapperOperation alloc] initWithRepresentation:(id)jSONData mappingsDictionary:mappingsDictionary];
mapperOperation.mappingOperationDataSource = mappingDataSource;
mapperOperation.delegate = self;
[manager.operationQueue addOperation:mapperOperation];
And:
- (void)mapperDidFinishMapping:(RKMapperOperation *)mapper {
NSError *error;
[((RKManagedObjectMappingOperationDataSource *)[mapper mappingOperationDataSource]).managedObjectContext save:&error];
}
Is there a known workaround for this? Or am I missing something?