1

I am working with MagicalRecord 2.2. Sometimes I receive 'CoreData could not fulfill a fault' crash in production code and I've created some test code to investigate this problem. Here is its description.

I have an entity "Object". At the start, I create one object on main thread, then I call [MagicalRecord saveWithBlock:...] where I fetch this object from local context and delete it. I added extra logging to the method (NSManagedObjectContext+MagicalSaves.m)

(void)MR_saveWithOptions:( MRSaveContextOptions)mask completion

// BEFORE REAL SAVE is placed before line 'saved = [self save:&error];'
// AFTER REAL SAVE is placed after it

// Logging code line is:
//
// NSManagedObjectContext *context = ... (defaultContext/rootContext/self)
// NSArray *objects = [context executeFetchRequest:[NSFetchRequest fetchRequestWithEntityName:@"Object"] error:NULL];
// NSLog(@"%i objects in %@ context (%@)",
//         [objects count],
//         context == [NSManagedObjectContext defaultContext] ? @"main" :
//         context == [NSManagedObjectContext MR_rootSavingContext] ? @"root" : @"local",
//         [NSThread isMainThread] ? @"MAIN" : @"BACKGROUND");

2014-07-04 23:07:32.322 MyApp[3661:1703] BEFORE REAL SAVE // Current context is local   
2014-07-04 23:07:32.325 MyApp[3661:1703] 1 objects in default context (BACKGROUND)
2014-07-04 23:07:32.325 MyApp[3661:1703] 1 objects in root context (BACKGROUND)
2014-07-04 23:07:32.326 MyApp[3661:1703] 0 objects in current context (BACKGROUND) // We deleted object before save, so all is ok
2014-07-04 23:07:32.327 MyApp[3661:1703] AFTER REAL SAVE // Line 'saved = [self save:&error];' was executed
2014-07-04 23:07:32.328 MyApp[3661:1703] 0 objects in default context (BACKGROUND) // Why is object deleted here? We didn't call save for parent context yet
2014-07-04 23:07:32.339 MyApp[3661:1703] 0 objects in root context (BACKGROUND) // Same here, why changes are immediately propagated to all contexts?
2014-07-04 23:07:32.340 MyApp[3661:1703] 0 objects in local context (BACKGROUND)
2014-07-04 23:07:32.340 MyApp[3661:1703] BEFORE REAL SAVE // This save was called for localContext.parentContext, so current context is root
2014-07-04 23:07:32.341 MyApp[3661:1703] 0 objects in default context (BACKGROUND) 
2014-07-04 23:07:32.341 MyApp[3661:1703] 0 objects in root context (BACKGROUND) // Before save there are no objects in root context 
2014-07-04 23:07:32.342 MyApp[3661:1703] 0 objects in root context (BACKGROUND)
2014-07-04 23:07:32.343 MyApp[3661:1703] AFTER REAL SAVE
2014-07-04 23:07:32.343 MyApp[3661:1703] 0 objects in default context (BACKGROUND)
2014-07-04 23:07:32.343 MyApp[3661:1703] 0 objects in root context (BACKGROUND)
2014-07-04 23:07:32.420 MyApp[3661:1703] 0 objects in root context (BACKGROUND)   

Maybe I misunderstand something? Why is default context modified on background?

In production code I have several places, when I handle async events (initiated by performSelectorOnMainThread, NSNotification, NSTimer) and should delete some objects with entity X. I call "saveWithBlock", where delete needed instances and in completion block post notification to update UI.

When I handle notification for UI update, I have code:

NSArray *objects = [Object findAll]; // #1
NSPredicate *unreadPredicate = [NSPredicate predicateWithFormat:@"isRead == %@", [NSNumber numberWithBool:NO]]; // #2
NSArray *unreadObjects = [objects filteredArrayUsingPredicate:unreadPredicate]; // #3

'CoreData could not fulfill a fault' crash is happened at line #3.

It seems, that some activity modifies "objects", posts "Update UI" notification, and at the same time other activity deletes some "objects" again. After objects were fetched at line #1, defaultContext was modified on background and filtering fails. This crash happens very rarely, but it happens.

How can I handle this situation?

  • Why are you findingAll and then filtering? Why not use -MR_findAllWithPredicate:@"isRead = NO"? – casademora Jul 06 '14 at 19:35
  • I can move predicate to FetchRequest, but if for some reason I had to iterate received objects and accumulate some information from them or do some other stuff and write more than 1 line of code, I would catch this crash again sometimes. So I want to understand what is going on and maybe my work approach is wrong? – user3810135 Jul 07 '14 at 06:44

0 Answers0