У меня есть приложение с основными данными с двумя представлениями. Первый вид перечисляет «Комнаты», второй - «Сцены» в комнатах. Страница Rooms имеет кнопку редактирования NavItem, которая при нажатии включает кнопку добавления NavItem. Вы можете удалять и добавлять номера отсюда. Добавленные комнаты просто отображаются с "Новой комнатой" по умолчанию имя в таблице. Второй вид - это список сцен в выбранной комнате. То же самое здесь, вы можете удалять и добавлять сцены, а добавленные сцены просто появляются в таблице с именем «Новая сцена». Ничего особенного на самом деле.
Я использую FetchedResultsController
в обоих контроллерах представления, при этом один из сцен имеет NSPredicate
, чтобы возвращать только сцены из выбранной комнаты. Я также использую методы делегирования controllerWillChangeContent
, controllerDidChangeContent
и т. Д. Сначала все работает нормально, но обычно после навигации по комнатам и сценам пытаясь удалить сцену, она потерпит крах. Он неизбежно потерпит крах, если вы поиграете с ним достаточно долго. Это происходит только при удалении сцены. Если вы нажмете кнопку редактирования и удалите сцену, и она сработает, то все последующие удаления в этом сеансе редактирования будут работать всегда. Это произойдет только при первом удалении сеанса редактирования.
Я получаю странную ошибку:
Завершение работы приложения из-за необработанного исключения 'NSInvalidArgumentException', причина: '- [__ NSCFType controllerWillChangeContent:]: нераспознанный селектор отправлен на экземпляр 0x5e02d70 '
Первая часть этой ошибки иногда изменяется. Иногда это __NSCFType
, иногда это CALayer
. Эта ошибка возникает только при удалении сцен. Добавление сцен - это нормально на 100%.
Я читал еще одну статью о потоке стека, в которой говорится, что такого рода ошибки могут возникать из-за проблем с управлением памятью. Я дважды проверил код, а также провел его через инструменты с помощью инструмента утечки. Утечек нет.
Есть ли что-нибудь еще, что я могу проверить? Есть идеи?
Вот соответствующий код ..
От ScenesTableViewController.m:
// used to show/hide the add button
- (void)setEditing:(BOOL)editing animated:(BOOL)animate
{
[super setEditing:editing animated:animate];
if(editing)
{
self.navigationItem.leftBarButtonItem = addButton;
}
else
{
self.navigationItem.leftBarButtonItem = nil;
}
}
// called when the add button is pressed
- (void)addAction {
NSEntityDescription *myContentEntity = [NSEntityDescription entityForName:@"Scene" inManagedObjectContext:managedObjectContext];
Scene *contentToSave = [[Scene alloc] initWithEntity:myContentEntity insertIntoManagedObjectContext:managedObjectContext];
[contentToSave setValue:@"New Scene" forKey:@"Name"];
[parentRoom addRoomToScenesObject:contentToSave];
NSError *error;
if (![managedObjectContext save:&error]) {
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
exit(-1);
}
[contentToSave release];
}
// delegate method that's being sent unrecognised selectors
- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller {
// The fetch controller is about to start sending change notifications, so prepare the table view for updates.
[self.tableView beginUpdates];
}
// cell display code
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = @"Cell";
UITableViewCell *cell = nil;
cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (!cell) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle
reuseIdentifier:CellIdentifier] autorelease];
[cell setAccessoryType:UITableViewCellAccessoryDisclosureIndicator];
}
[self configureCell:cell atIndexPath:indexPath];
return cell;
}
- (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath {
NSManagedObject *mo = nil;
NSString *temp = nil;
mo = [fetchedResultsController objectAtIndexPath:indexPath];
temp = [mo valueForKey:@"Name"];
[[cell textLabel] setText:temp];
}
// cell editing code
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
// Delete the managed object at the given index path.
[managedObjectContext deleteObject:[fetchedResultsController objectAtIndexPath:indexPath]];
NSError *error;
if (![managedObjectContext save:&error]) {
// Update to handle the error appropriately.
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
exit(-1); // Fail
}
}
else if (editingStyle == UITableViewCellEditingStyleInsert) {
// Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view
}
}
// NSFetchedResultsController code
- (NSFetchedResultsController *)fetchedResultsController {
if (fetchedResultsController != nil) {
return fetchedResultsController;
}
/*
Set up the fetched results controller.
*/
// Create the fetch request for the entity.
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
// Edit the entity name as appropriate.
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Scene" inManagedObjectContext:managedObjectContext];
NSSortDescriptor *nameDescriptor = [[NSSortDescriptor alloc] initWithKey:@"Name" ascending:YES];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:nameDescriptor, nil];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"(SceneToRoom == %@)", parentRoom];
[fetchRequest setSortDescriptors:sortDescriptors];
[fetchRequest setPredicate:predicate];
[fetchRequest setEntity:entity];
// Edit the section name key path and cache name if appropriate.
// nil for section name key path means "no sections".
NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:managedObjectContext sectionNameKeyPath:nil cacheName:nil];
aFetchedResultsController.delegate = self;
self.fetchedResultsController = aFetchedResultsController;
[aFetchedResultsController release];
[fetchRequest release];
[nameDescriptor release];
[sortDescriptors release];
return fetchedResultsController;
}
Эта ошибка, скорее всего, исходит от NSFetchedResultsController
, у которого есть освобожденный делегат. У вас есть UIViewController
, который вы выпустили и не выпустили связанный NSFetchedResultsController
?