Я получаю устаревшие результаты при выполнении запроса на выборку NSManagedObjectContextObjectsDidChangeNotification
.
В качестве примера рассмотрим каталоги с документами, которые можно удалить логически с помощью логического атрибута (softDeleted
). Запрос на выборку должен возвращать все каталоги, в которых есть хотя бы один неудаленный документ (directoriesWithDocuments
).
Исходное состояние — один каталог с одним удаленным документом. directoriesWithDocuments
возвращает пустой массив.
Следующий код восстанавливает документ, присваивая логическому значению softDeleted
значение NO
.
[_context.undoManager beginUndoGrouping];
[_context.undoManager setActionName:@"undelete"];
document.softDeleted = @(NO);
NSError *error;
BOOL success = [_context save:&error]; // This triggers the notification
[_context.undoManager endUndoGrouping];
Сохранение вызывает NSManagedObjectContextObjectsDidChangeNotification
. Я ожидал, что directoriesWithDocuments
вернет каталог, но вместо этого он по-прежнему возвращает пустой массив.
- (void)objectsDidChangeNotification:(NSNotification*)notification
{
NSArray *objects = [self directoriesWithDocuments]; // Still empty!
}
Тем не менее, если я выполню directoriesWithDocuments
после сохранения контекста либо сразу, либо в следующем цикле выполнения, он вернет каталог, как и ожидалось.
Это код запроса на выборку:
- (NSArray*)directoriesWithDocuments
{
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"ANY documents.softDeleted == NO"];
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"Directory"];
fetchRequest.predicate = predicate;
fetchRequest.includesPendingChanges = YES; // Just in case
NSError *error = nil;
NSArray *objects = [_context executeFetchRequest:fetchRequest error:&error];
return directories;
}
Я подозреваю, что в контексте есть какой-то кеш для запросов на выборку, который не очищается до тех пор, пока не будет обработано уведомление. Ожидается ли, что Core Data будет вести себя именно так? Или я что-то не так делаю?
Обходной путь
В настоящее время я задерживаю выполнение запроса на выборку следующим образом:
- (void)objectsDidChangeNotification:(NSNotification*)notification
{
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
// HACK: Give time to Core Data to process pending changes or invalidate caches
NSArray *objects = [self directoriesWithDocuments]; // Returns the directory as expected
}];
}
Эксперименты
По предложению @MikePollard я проверил возвращаемое значение directoriesWithDocuments
в NSManagedObjectContextWillSaveNotification
и NSManagedObjectContextDidSaveNotification
. Результаты (по порядку):
NSManagedObjectContextObjectsDidChangeNotification
: пусто (неверно)NSManagedObjectContextWillSaveNotification
: пусто (неверно)NSManagedObjectContextDidSaveNotification
: 1 каталог (правильно)
directoriesWithDocuments
в результатеNSManagedObjectContextWillSaveNotification
, а также уведомленияNSManagedObjectContextDidSaveNotification
? - person Mike Pollard   schedule 06.03.2014-com.apple.CoreData.SQLDebug 1
, вы увидите оператор SQL. - person Mike Pollard   schedule 06.03.2014NSManagedObjectContextObjectsDidChangeNotification
небезопасно. - person hpique   schedule 06.03.2014