Это еще один случай, когда вызов performFetch
на NSFetchedResultController
прерывается с исключением, говорящим:
ФАТАЛЬНАЯ ОШИБКА: Постоянный кэш информации раздела не соответствует текущей конфигурации. Вы незаконно мутировали запрос выборки NSFetchedResultsController, его предикат или дескриптор его сортировки, не отключая кэширование и не используя + deleteCacheWithName:
За исключением того, что я этого не делал. Чтобы понять проблему, посмотрите на предикат:
предикат: (collection.identifier == "; root" AND doc.status == 0);
Теперь посмотрите на несоответствующее содержимое кэша:
cached objects were: (
"MyDocument 'PL00002.jpeg' in set '/' (#2147483647)",
"MyDocument 'PL00003.jpeg' in set '/' (#2147483647)",
"MyDocument 'PL00003.pdf' in set '/' (#2147483647)",
"MyDocument 'PL00002.pdf' in set '/' (#2147483647)"
)
fetched objects are: (
"MyDocument 'PL00002.jpeg' in set '/' (#2147483647)",
"MyDocument 'PL00003.jpeg' in set '/' (#2147483647)",
"MyDocument 'PL00004.jpeg' in set '/' (#2147483647)",
"MyDocument 'PL00003.pdf' in set '/' (#2147483647)",
"MyDocument 'PL00002.pdf' in set '/' (#2147483647)",
"MyDocument 'PL00004.pdf' in set '/' (#2147483647)"
)
Действительно, есть два новых подходящих объекта. Причина в том, что два новых объекта (PL00004.jpeg
и PL00004.pdf
) ранее имели свойство status
на значение <> 0, и я изменил их status
обратно на 0 в коде, потому что они начали удовлетворять некоторому внешнему условию (не вызывается действием пользователя).
Для полноты вот код, вызывающий исключение:
- (void) reloadData
{
NSError *error = nil;
if (![[self fetchedResultsController] performFetch:&error]) {
abort(); // I have actually better error handling
}
[_gridView reloadData];
}
также обратите внимание:
- нет других
NSFetchedResultController
использует кэш с тем же именем
_gridView
не является UITableView
, хотя он также отображает коллекцию сущностей. Эта деталь не должна быть актуальной.
- ни один из
NSFetchedResultController
методов делегатов никогда не вызывается, особенно когда я изменяю статус двух моих объектов на 0
- все работает нормально, если я очищаю кэш до
performFetch:
(или без кэширования).
- Я вызываю этот метод
reloadData
на моем контроллере по окончании периодической проверки того внешнего состояния, о котором я упоминал выше.
-
NSFetchedResultController
создается с nil
sectionNameKeyPath
.
- Как объяснено, я никогда не изменяю
fetchedResultsController
: ни предикат, ни запрос на выборку, ни порядок сортировки, ничего.
Я не думаю, что должен получить это исключение просто потому, что новые объекты теперь удовлетворяют предикату. Удаление кеша позволяет избежать исключения, но пока я не понимаю, почему я должен это делать, я не считаю это исправлением .
Есть идеи, что мне здесь не хватает?
Редактировать: вот запрашиваемая информация:
Код для установки NSFetchedResultController
. Когда пользователь выбирает коллекцию, это называется:
- (void) displayCollection:(Collection *)aSet
{
self.currentCollection = aSet;
NSFetchRequest *fetchRequest = [[self fetchedResultsController] fetchRequest];
NSString *collectionIdentifier = @";root"; // no selection is like "select root collection";
if (aSet) {
collectionIdentifier = aSet.identifier;
}
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"collection.identifier == %@ and doc.status == %d", collectionIdentifier, upToDate];
[fetchRequest setPredicate:predicate];
[NSFetchedResultsController deleteCacheWithName:cacheName];
NSError *error = nil;
if (![[self fetchedResultsController] performFetch:&error]) {
abort(); // whatever
}
[_gridView reloadData];
}
fetchedResultsController
было инициализировано так:
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"DocInCollection" inManagedObjectContext:managedObjectContext];
[fetchRequest setEntity:entity];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"collection.identifier == %@ and doc.status == %d", @";root", upToDate];
[fetchRequest setPredicate:predicate];
[fetchRequest setFetchBatchSize:20];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"position" ascending:YES];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
[fetchRequest setSortDescriptors:sortDescriptors];
NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:managedObjectContext sectionNameKeyPath:nil cacheName:cacheName];
Код, который вызывается при обновлении doc.status
:
- (void) setUpToDate
{
self.status = [NSNumber numberWithInt:upToDate];
NSError *error = nil;
[[self managedObjectContext] save:&error];
if (error) { } // whatever
[[self managedObjectContext] processPendingChanges];
}
cacheName
- это глобальная константа NSString
, upToDate
- это константа перечисления (0).
Наконец, модель немного сложна из-за других сущностей, которые используются приложением. Вот упрощенная версия:
модель http://emberapp.com/jdmuys/images/untitled-1/sizes/m.png