У меня есть UIManagedDocument
с некоторыми данными, которые я отображаю в списке, используя NSFetchedResultsController
. Данные регулярно обновляются в фоновом режиме, и изменения помещаются в UIManagedDocument.managedObjectContext
(используя PerformBlock:).
Когда я отображаю данные из основного контекста документа, все работает как положено. Но как только я отображаю список в контексте, который является дочерним по отношению к основному контексту (child.parentContext = document.managedObjectContext
), я не вижу никаких объектов, и в консоли выводится следующая ошибка:
foo[17895:15203] CoreData: error: (NSFetchedResultsController)
The fetched object at index 5 has an out of order section name 'E.
Objects must be sorted by section name'
Это происходит только после того, как новый объект был вставлен в контакт документов. Когда я достаточно долго жду автоматического сохранения, список отображается нормально. Также проблема возникает только тогда, когда у меня установлен sectionNameKeyPath
на NSFetchedResultsController
и только с дочерним контекстом.
Вот как я настраиваю полученный контроллер результатов, ничего особенного, поэтому я не вижу, что я мог сделать здесь неправильно:
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:@"Contact"];
fetchRequest.sortDescriptors = [Contact userDefinedSortDescriptors];
fetchRequest.predicate = [NSPredicate predicateWithFormat:@"hidden == nil || hidden == NO"];
NSFetchedResultsController *fetchedResultsController =
[[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
managedObjectContext:_managedObjectContext
sectionNameKeyPath:[Contact userDefinedSectionNameKeyPath]
cacheName:@"ContactList"];
[Contact userDefinedSortDescriptors]
и [Contact userDefinedSectionNameKeyPath]
разрешаются во время выполнения. Дескрипторы сортировки содержат в качестве первой записи sectionNameKeyPath. Также не может быть nil
или других забавных вещей.
Изменить: уточнены некоторые неясные моменты. В частности, я не вызываю -save: в контексте управляемого объекта документов.
Редактировать 2: я попытаюсь объяснить, как MOC связаны друг с другом.
В игре есть три контекста управляемых объектов:
1) UIManagedDocument.managedObjectContext
создается путем загрузки документа.
2) Работает фоновый поток, который время от времени обновляет объекты. Это moc частной очереди с документами MOC в качестве родителя:
context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
context.parentContext = repository.managedObjectContext;
[context performBlock:^{ /* updates */ }];
[context performBlock:^{ [context save:NULL]; }];
3) Когда пользователь хочет внести изменения, создается новый MOC как дочерний элемент MOC документа. Это MOC основной очереди. Это контекст, который используется для выполнения показанной выше выборки.
Фоновые обновления выполняются из NSOperationQueue, но весь доступ к фоновому MOC правильно окружен -performBlock:
. Все остальные обращения выполняются из основного потока.
Редактировать 3. Играя с некоторыми настройками на NSFetchRequest
, я обнаружил, что проблема исчезает при настройке fetchRequest.includesPendingChanges = NO
. Но это нежизнеспособное решение, потому что теперь пользователь больше не видит никаких обновлений, пока изменения не будут сохранены в фоновом режиме с помощью UIManagedDocument.