Табличное представление на основе NSFetchedResultsController всегда терпит неудачу при ВТОРОЙ вставке объекта

StackOverflow https://stackoverflow.com/questions/2242011

Вопрос

Я использую NSFetchedResultsController для управления отображением выбранных управляемых объектов в табличном представлении, имеющем один раздел.Таблица изначально пуста, и пользователь может добавлять в нее новые сущности с помощью пользовательского интерфейса.В нынешнем виде программа всегда работает при добавлении первой сущности и всегда вылетает при добавлении второй.Иногда при сбое ошибка не появляется, а иногда возникают ошибки разных типов (некоторые из них указаны ниже).С помощью операторов журнала и трассировки я вижу, что программа аварийно завершает работу сразу после завершения работы метода ControllerWillChangeContent делегата NSFetchResultsController (который вызывает [self.tableView BeginUpdates];), но до вызова любого другого метода в моем коде.Вот некоторые из соответствующих частей моего кода.Настройка NSFetchedResultsController:

NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
[fetchRequest setEntity:[NSEntityDescription entityForName:@"Beer"
                                    inManagedObjectContext:self.managedObjectContext]];

// Configure request's entity and predicate
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"name" ascending:YES];
NSArray *sortDescriptors = [NSArray arrayWithObjects:sortDescriptor, nil];
[fetchRequest setSortDescriptors:sortDescriptors];
[sortDescriptor release];
[sortDescriptors release];

NSString *expression = [NSString stringWithFormat:@"brewery.name LIKE \"%@\"", self.brewery.name];
NSPredicate *predicate = [NSPredicate predicateWithFormat:expression];
[fetchRequest setPredicate:predicate];
self.resultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
                                                             managedObjectContext:self.managedObjectContext
                                                               sectionNameKeyPath:nil
                                                                        cacheName:nil];
self.resultsController.delegate = self;
[fetchRequest release];

NSError *error = nil;
BOOL success = [resultsController performFetch:&error];
if (!success) {
    NSLog(@"Error fetching request %@", [error localizedDescription]);
}

Добавляем новую сущность:

NSEntityDescription *entity = [NSEntityDescription entityForName:@"Beer" inManagedObjectContext:self.managedObjectContext];
Beer *beer = [[Beer alloc] initWithEntity:entity insertIntoManagedObjectContext:self.managedObjectContext];
beer.name = beerName;
beer.brewery = self.brewery;

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

Некоторые из ошибок, которые я получил:

Serious application error.  Exception was caught during Core Data change processing: *** -[NSCFString compareObject:toObject:]: unrecognized selector sent to instance 0x4e808c0 with userInfo (null)
Serious application error.  Exception was caught during Core Data change processing: *** -[CALayer compareObject:toObject:]: unrecognized selector sent to instance 0x4e53b80 with userInfo (null)
Serious application error.  Exception was caught during Core Data change processing: *** -[UITextTapRecognizer controllerWillChangeContent:]: unrecognized selector sent to instance 0x4ca5d70 with userInfo (null)
Serious application error.  Exception was caught during Core Data change processing: *** -[CALayer controllerWillChangeContent:]: unrecognized selector sent to instance 0x4e271a0 with userInfo (null)
Serious application error.  Exception was caught during Core Data change processing: *** -[NSCFNumber countByEnumeratingWithState:objects:count:]: unrecognized selector sent to instance 0x4c96ee0 with userInfo (null)

Как видите, ошибки (когда они были представлены) непоследовательны, даже если в код не было внесено никаких изменений.

Может ли кто-нибудь понять, что я делаю неправильно?

Это было полезно?

Решение

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

Я бы сделал следующее:

  1. Включи НСЗомби
  2. Добавьте точку останова для objc_exception_throw
  3. Запустить в отладчике

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

Лучше всего обновить исходный вопрос дополнительной информацией.

Другие советы

Ваш код для создания новых сущностей странный.А как насчет использования этого вместо этого:

Beer* beer = [NSEntityDescription insertNewObjectForEntityForName: @"Beer" 
    inManagedObjectContext: self.managedObjectContext];
beer.name = @"Grolsch";

И еще ты не звонишь NSManagedObjectContext#save:.Но, может быть, вы делаете это в той части вашего кода, которую сейчас показали?

Хотя я и не решил эту конкретную проблему, я применил немного другой подход к написанию класса, который предоставлял нужную мне функциональность и не вызывал возникновения проблемы.Я все еще использую NSFetchedResultsController, но вместо реализации всех четырех методов делегата я реализую только контроллерDidChangeContent:, который просто вызывает [tableView reloadData].

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

Недавно у меня была похожая ошибка - ваша проблема связана с чрезмерным выпуском, в частности:

[sortDescriptors release];

Вы получаете объект sortDescriptors из

[NSArray arrayWithObjects:sortDescriptor, nil];

у которого нет «alloc», «copy» или «new», поэтому он возвращает автоматически высвобождаемый объект.Поскольку вы выпускаете его раньше, у вас есть два места, где может произойти сбой: когда NSFetchRequest использует его и когда он выпускается пулом.Увидеть яблоко руководство по управлению памятью Больше подробностей.

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

Сообщения об ошибках были разными, но в основном они были связаны с селектором CompareObject:toObject, как показано ниже.

-[_НСКФСет сравненияОбъект:тоОбъект:]:Непознанный селектор, отправленный в экземпляр -[_NSCFString CompareObject:toObject:] нераспознанный селектор отправлен в экземпляр

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

Удачи!Рог

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top