Сбой NSFetchedResultsController на executeFetch: при использовании кэша - PullRequest
47 голосов
/ 26 апреля 2010

Я использую NSFetchedResultsController для отображения группы объектов, которые разделены по датам. При новой установке все работает отлично, и объекты отображаются в виде таблицы. Тем не менее, кажется, что при перезапуске приложения происходит сбой. Я указываю кэш при инициализации NSFetchedResultsController, а когда нет, он отлично работает.

Вот как я создаю свой NSFetchedResultsController:

- (NSFetchedResultsController *)results {
    // If we are not nil, stop here
    if (results != nil)
        return results;

    // Create the fetch request, entity and sort descriptors
    NSFetchRequest *fetch = [[NSFetchRequest alloc] init];
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"Event" inManagedObjectContext:self.managedObjectContext];
    NSSortDescriptor *descriptor = [[NSSortDescriptor alloc] initWithKey:@"utc_start" ascending:YES];
    NSArray *descriptors = [[NSArray alloc] initWithObjects:descriptor, nil];

    // Set properties on the fetch
    [fetch setEntity:entity];
    [fetch setSortDescriptors:descriptors];

    // Create a fresh fetched results controller
    NSFetchedResultsController *fetched = [[NSFetchedResultsController alloc] initWithFetchRequest:fetch managedObjectContext:self.managedObjectContext sectionNameKeyPath:@"day" cacheName:@"Events"];
    fetched.delegate = self;
    self.results = fetched;

    // Release objects and return our controller
    [fetched release];
    [fetch release];
    [descriptor release];
    [descriptors release];
    return results;
}

Это сообщения, которые я получаю при сбое приложения:

FATAL ERROR: The persistent cache of section information does not match the current configuration.  You have illegally mutated the NSFetchedResultsController's fetch request, its predicate, or its sort descriptor without either disabling caching or using +deleteCacheWithName:
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'FATAL ERROR: The persistent cache of section information does not match the current configuration.  You have illegally mutated the NSFetchedResultsController's fetch request, its predicate, or its sort descriptor without either disabling caching or using +deleteCacheWithName:'

Я действительно понятия не имею, почему он так говорит, поскольку не верю, что делаю что-то особенное, что могло бы вызвать это. Единственная потенциальная проблема - заголовок раздела (день), который я создаю при создании нового объекта следующим образом:

// Set the new format
[formatter setDateFormat:@"dd MMMM"];

// Set the day of the event
[event setValue:[formatter stringFromDate:[event valueForKey:@"utc_start"]] forKey:@"day"];

Как я уже говорил, все это прекрасно работает, если кеш не задействован. Любая помощь приветствуется!

Ответы [ 12 ]

65 голосов
/ 29 июля 2010

У меня была похожая проблема с одним из моих приложений, когда Apple выпустила новую iOS 4.0. Поиск:

fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:[self managedObjectContext] sectionNameKeyPath:nil cacheName:nil];

И установите значение параметра cacheName равным nil. Это сработало для меня, надеюсь, это будет для вас. Дайте мне знать.

30 голосов
/ 02 августа 2010

Я начал получать ту же ошибку при обновлении MacBook Pro до Snow Leopard 10.6.4 и последней версии SDK.

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

В частности, когда вы выбираете вещи, они кэшируются, а в 4.0 этот кэш не очищается автоматически в тех случаях, когда он очищался в более раннем SDK.

Для меня решение было простым. Я просто использовал метод класса, который очищает кэши. Вы можете указать отдельную сущность, но я указываю ноль, так что он просто делает их все в этом конкретном фрагменте кода запуска:

[NSFetchedResultsController deleteCacheWithName:nil];

Внезапно небольшое приложение, над которым я работал только для ознакомления с CoreData, снова работает.

15 голосов
/ 01 января 2012

Прямо из документации на NSFetchedResultsController:

Изменение запроса на выборку

Вы не можете просто изменить запрос на выборку изменить результаты. Если вы хотите изменить запрос на выборку, вы должен:

  1. Если вы используете кеш, удалите его (используя deleteCacheWithName:). Обычно вы не должны использовать кеш, если вы меняете выборку запрос.

  2. Изменить запрос на выборку.

  3. Invoke performFetch:.

6 голосов
/ 10 марта 2011

Я столкнулся с подобной проблемой. Когда я осмотрел консоль отладчика, она показала, что такое кэшированные объекты и извлеченные объекты, чтобы я мог выяснить, почему они несовместимы. В моем случае это было связано с другим предикатом.

Поскольку значения в моем предикате не являются динамическими, я мог бы указать другое имя кэша для каждого предиката. Это создаст кеш для каждого указанного мной типа.

Полагаю, вам придется оценить вашу потребность в кеше. Чтобы указать nil, означает, что выборка производится при каждом вызове.

Я понял, что ошибка возникает только тогда, когда в запросе на выборку есть какие-то изменения. Если вы создаете новый NSFetchRequest ИЛИ изменяя дескриптор сортировки предиката ИЛИ, то вам следует удалить кеш или использовать другой кеш. В противном случае, убедитесь, что у вас есть тот же NSFetchRequest или что ваш NSFetchedResultsController сохранен, и это должно решить вашу проблему.

3 голосов
/ 07 августа 2015

Исключение все еще происходит с Xcode 7 (бета 4):

Вы незаконно мутировали выборку NSFetchedResultsController запрос, его предикат или дескриптор его сортировки без отключение кэширования или использование + deleteCacheWithName:

ПРИМЕЧАНИЕ: Это с немодифицированным приложением Xcode "Template" Master-Detail для iOS со стандартным Xcode CoreData "кодовая панель" код, созданный с помощью Xcode 7 и с использованием последней (iOS 9) цели развертывания.

Я впервые заметил это, когда перезапустил свое приложение в симуляторе. Я запускал и останавливал приложение несколько раз через XCode, и затем это случилось; и это продолжало происходить. Я решил сделать несколько экспериментов, и результаты:

  • Каждый раз, когда я останавливал приложение в симуляторе, я получал исключение при последующем запуске.
  • Каждый раз, когда я останавливал приложение с помощью кнопки Home на симуляторе, я мог успешно запустить его снова.

Проблема по-прежнему может быть устранена следующим образом , используя один или другой из следующих методов:

  • В методе AppDelegate application didFinishLaunchingWithOptions добавьте следующий код Swift NSFetchedResultsController.deleteCacheWithName(nil) или Objective-C [NSFetchedResultsController deleteCacheWithName:nil];. Это очищает поврежденный кеш.
  • В Simulator, из меню Simulator выберите Сбросить содержимое и настройки . Это решает проблему, но вы теряете свои тестовые данные .

Я также считаю, что это артефакт работы через Xcode и остановки приложения до того, как оно сможет очиститься. Я не видел этого в реальном устройстве.

3 голосов
/ 26 апреля 2010

Если вы используете симулятор, попробуйте сбросить его - я думаю, вы изменили свою карту сущностей, и она запуталась в оставшемся кеше. Если нет, вы можете попробовать сделать то, что говорит ошибка:

- (void)applicationWillTerminate:(UIApplication *)application {
    [NSFetchedResultsController deleteCacheNamed:@"Events"];
    //etc
}
1 голос
/ 29 июля 2015

Я нашел на форумах Ray Wenderlich that

Обратите внимание, что сбой происходит только тогда, когда запрос на выборку еще не создан, когда вы добавляете что-то новое в хранилище данных , то есть, когда представление Locations еще не загружено. Если представление уже загружено, то оно работает нормально. Странно, а?

Итак, в моем случае произошло следующее:

  1. Обычный процесс запуска влечет за собой создание NSFetchedResultsController.
  2. Поскольку извлекаются тысячи объектов, новая выборка занимает значительное время. Чтобы смягчить это, выборка a) использует кеш, и b) происходит в фоновом режиме, позволяя другим действиям продолжить
  3. Обычно, хотя пользовательский интерфейс отзывчив и пользователь может что-то делать, выборка завершается задолго до того, как пользователь может выразить желание создать новый объект.
  4. Однако иногда приложение будет запускаться в фоновом режиме - скажем, из события WatchKit или из фоновой выборки и т. Д.), И часть запуска повлечет за собой немедленное создание нового объекта в хранилище данных.
  5. Если новый объект был создан до завершения выборки, приложение зависнет.

Решение состоит в том, чтобы убедиться, что Выборка завершена до создания объекта (что повлияет на выборку).

В качестве альтернативы вы можете удалить кеш, но на практике это менее производительно.

Обратите внимание, что предупреждение отладчика, что

Вы незаконно мутировали запрос выборки NSFetchedResultsController, его предикат или дескриптор сортировки, не отключая кэширование и не используя + deleteCacheWithName:

просто не фиксирует эту ситуацию вообще, потому что то, что вы изменили, не было дескриптором запроса, предиката или сортировки, но, точнее, можно было бы описать, как мутировало результирующий набор во время выполнения выборки .

Мне потребовалось целую вечность, чтобы разыскать этот маленький кусочек пустяков. Я надеюсь, что вы выиграете.

1 голос
/ 16 мая 2014

Для тех, кто сталкивается с той же проблемой в настоящее время, проблема в том, что каким-то образом Core Data не очищает кэш, поэтому сначала работает нормально, но после этого не работает. Затем просто поместите эту строку сразу после инициализации NSFetchRequest

[NSFetchedResultsController deleteCacheWithName:@"Name"];
1 голос
/ 07 января 2012

У меня была такая же проблема.
Чтобы исправить, я поставил [NSFetchedResultsController deleteCacheWithName:@"cacheName"]; перед инициализацией результатов контроллера. У меня работает, так как он идет туда только в первый раз.

1 голос
/ 26 июня 2010

Сколько классов реализует один и тот же - (NSFetchedResultsController *) метод результатов, используете ли вы для каждого отдельный кэш? У меня была та же проблема, и я думаю, что я исправляю ее, используя другое имя кэша для некоторых предложений, поскольку у меня разные NSPredicates.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...