Ошибка ‘CoreData не удалось выполнить ошибку’ с MagicalRecord

#ios #core-data #magicalrecord

#iOS #core-data #magicalrecord

Вопрос:

Я работаю с MagicalRecord 2.2. Иногда я получаю сбой ‘CoreData не удалось выполнить ошибку’ в производственном коде, и я создал некоторый тестовый код для изучения этой проблемы. Вот ее описание.

У меня есть объект «Object». Вначале я создаю один объект в главном потоке, затем вызываю [MagicalRecord saveWithBlock:…], где я извлекаю этот объект из локального контекста и удаляю его. Я добавил дополнительное ведение журнала в метод (NSManagedObjectContext MagicalSaves.m)

(недействительно)MR_saveWithOptions: ( MRSaveContextOptions) завершение маски

 // BEFORE REAL SAVE is placed before line 'saved = [self save:amp;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:amp;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)   
  

Может быть, я что-то неправильно понимаю? Почему контекст по умолчанию изменяется в фоновом режиме?

В производственном коде у меня есть несколько мест, когда я обрабатываю асинхронные события (инициируемые performSelectorOnMainThread, NSNotification, NSTimer) и должен удалять некоторые объекты с помощью entity X. Я вызываю «saveWithBlock», где удаляю необходимые экземпляры и по завершении блокирую post notification для обновления пользовательского интерфейса.

Когда я обрабатываю уведомление об обновлении пользовательского интерфейса, у меня есть код:

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

Сбой ‘CoreData не удалось выполнить ошибку’ произошел в строке # 3.

Кажется, что какое-то действие изменяет «объекты», публикует уведомление «Обновить пользовательский интерфейс», и в то же время другое действие снова удаляет некоторые «объекты». После того, как объекты были извлечены в строке # 1, defaultContext был изменен в фоновом режиме, и фильтрация завершилась с ошибкой. Этот сбой случается очень редко, но это случается.

Как я могу справиться с этой ситуацией?

Комментарии:

1. Почему вы находите все, а затем фильтруете? Почему бы не использовать -MR_findAllWithPredicate:@»isRead = NO»?

2. Я могу переместить predicate в fetchRequest, но если по какой-то причине мне приходилось повторять полученные объекты и накапливать из них некоторую информацию или делать что-то другое и писать более 1 строки кода, я иногда снова сталкивался с этим сбоем. Итак, я хочу понять, что происходит, и, возможно, мой подход к работе неправильный?