Подтвердить что ты не робот

NSFetchedResultsController crash on performFetch: при использовании кеша

Я использую 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 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 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"];

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

4b9b3361

Ответ 1

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

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

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

Ответ 2

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

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

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

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

[NSFetchedResultsController deleteCacheWithName:nil];

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

Ответ 3

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

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

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

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

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

  • Вызвать performFetch:.

Ответ 4

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

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

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

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

Ответ 5

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

- (void)applicationWillTerminate:(UIApplication *)application {
    [NSFetchedResultsController deleteCacheNamed:@"Events"];
    //etc
}

Ответ 6

Исключение по-прежнему происходит с Xcode 7 (beta 4):

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

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

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

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

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

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

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

Ответ 7

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

Ответ 8

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

Ответ 9

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

Ответ 10

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

[NSFetchedResultsController deleteCacheWithName:@"Name"];

Ответ 11

Я нашел через Ray Wenderlich forums, что

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

Итак, что случилось в моем случае:

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

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

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

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

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

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

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

Ответ 12

NSFetchedResultsController *fetched = [[NSFetchedResultsController alloc] initWithFetchRequest:fetch managedObjectContext:self.managedObjectContext sectionNameKeyPath:@"day" cacheName:@"Events"];

заменить @ "События" на ноль.