我有一个包含2个视图的核心数据应用。第一个视图列出“房间”,第二个视图列出房间中的“场景”。 “房间”页面有一个编辑NavItem按钮,按下该按钮可启用添加NavItem按钮。您可以从此处删除和添加房间。添加的房间只是在表格中显示默认的“新房间”名称。第二个视图是所选房间中的场景列表。同样在这里,您可以删除和添加场景,添加的场景只会出现在名为“新场景”的表格中。没什么特别的。
我在两个视图控制器中都使用FetchedResultsController
,其中一个场景NSPredicate
只返回所选房间的场景。我还使用controllerWillChangeContent
,controllerDidChangeContent
等委托方法进行表格视图更新。
这一切都很好,但通常在房间和场景周围导航然后尝试删除一个场景它会崩溃。如果你玩的时间足够长,它将不可避免地崩溃。它只在删除场景时发生。如果您按下编辑按钮并删除一个场景并且它可以正常工作,则该编辑会话中的所有以下删除操作将始终有效。它只会在第一次删除编辑会话时崩溃。
我得到的错误很奇怪:
由于未捕获的异常而终止应用 'NSInvalidArgumentException',原因:' - [__ NSCFType controllerWillChangeContent:]:发送到实例的无法识别的选择器 0x5e02d70'
此错误的第一部分有时会发生变化。有时它是__NSCFType
,有时它是CALayer
。仅在删除场景时才会出现此错误。添加场景很好100%。
我已经阅读了有关stackoverflow的另一篇文章,该文章表明这些错误可能来自内存管理问题。我已经仔细检查了代码,并通过仪器与泄漏仪器一起运行。没有泄漏。
还有什么我可以检查的吗?有什么想法吗?
以下是相关代码..
来自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;
}
答案 0 :(得分:28)
该错误很可能来自具有已发布委托的NSFetchedResultsController
。您是否已发布UIViewController
并且未发布关联的NSFetchedResultsController
?
答案 1 :(得分:1)
即使我遇到同样的问题。但对于iOS 4.2,问题是NSError
被初始化,因此它被视为垃圾,而在更新/插入时我们有
if (![managedObjectContext save:&error]) {
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
exit(-1);
}
因此在保存时,iOS将错误视为垃圾,因此异常。尝试将其初始化为零。它解决了我的问题。只有4.2iOS才能看到这个问题。