0

我已经阅读了几个处理类似问题的线程,但我无法弄清楚我过度释放了什么。从一个Player对象的详细视图控制器,我推一个UITableViewController以选择播放器位置的对象:第二次保存NSManagedObjectContext时出错(解除分配的insance)

- (void)selectLocations 
{ 
    LocationSelectionController *vc = [[LocationSelectionController alloc] initWithStyle:UITableViewStyleGrouped]; 
    vc.player = player; 
    [self.navigationController pushViewController:vc animated:YES]; 
    [vc release]; 
} 

这里看看LocationSelectionController的一些细节:

- (void)saveContext { 
    NSManagedObjectContext *context = [player managedObjectContext]; 
    if ([context hasChanges]) { 
    NSError *error = nil; 
     if (![context save:&error]) { //*** ERROR HERE *** 
      // show alert 
     } 
    } 
} 

- (void)viewDidLoad { 
    [super viewDidLoad]; 
    // .... 

    NSError *error = nil; 
    if (![[self fetchedResultsController] performFetch:&error]) { 
     // show alert 
    } 
} 

- (NSFetchedResultsController *)fetchedResultsController { 
    if (_fetchedResultsController != nil) { 
     return _fetchedResultsController; 
    } 
    NSManagedObjectContext *context = [player managedObjectContext]; 
    NSFetchRequest *request = [[NSFetchRequest alloc] init]; 
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"Location" inManagedObjectContext:context]; 
    [request setEntity:entity]; 

    NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"name" ascending:YES selector:@selector(caseInsensitiveCompare:)]; 
    NSArray *sortDescriptors = [NSArray arrayWithObjects:sortDescriptor, nil]; 
    [request setSortDescriptors:sortDescriptors]; 

    NSFetchedResultsController *aFRC = [[NSFetchedResultsController alloc] initWithFetchRequest:request managedObjectContext:context sectionNameKeyPath:nil cacheName:nil]; 
    aFRC.delegate = self; 
    self.fetchedResultsController = aFRC; 

    [request release]; 
    [sortDescriptor release]; 

    return _fetchedResultsController; 
} 

- (void)viewDidUnload { 
    [super viewDidUnload]; 
    self.fetchedResultsController = nil; 
} 


- (void)dealloc { 
    self.fetchedResultsController = nil; 
    [_fetchedResultsController release]; 
    [player release]; 
    [super dealloc]; 
} 

的功能第一次导航到LocationSelectionController时总是非常完美。我可以与Location对象进行交互,完全没有问题。当我弹出视图并返回到Player对象的详细视图时,再次有完美的功能。只有当我再次推送LocationSelectionController(即使它来自不同的Player对象),才会尝试保存上下文时发生崩溃。

*** -[LocationSelectionController controllerWillChangeContent:]: message sent to deallocated instance 0x7026920 

我一直在使用的仪器与NSZombie发现问题试过了,它指向我LocationSelectionController的一个实例。 Instruments Screen

回答

1

你对NSFetchedResultsController的处理是搞砸了。首先,考虑下面的代码:

NSFetchedResultsController *aFRC = [[NSFetchedResultsController alloc] initWithFetchRequest:request managedObjectContext:context sectionNameKeyPath:nil cacheName:nil]; 
aFRC.delegate = self; 
self.fetchedResultsController = aFRC; 

如果您fetchedResultsController属性声明assign,该代码是或多或少正确的(尽管随后的语义是错误的)。如果该房产被宣布为retain,则此处泄漏对aFRC的引用。

但无论如何,您的释放是错误的。在dealloc中,你有这样的:

self.fetchedResultsController = nil; 
[_fetchedResultsController release]; 

第一行设置属性(这大概是_fetchedResultsController伊娃)为零,所以第二行不能释放对象。如果财产被宣布为retain,我想这是一个尝试清理上面提到的泄漏;如果它被声明为assign,这是上述错误语义的证据。即使这个工作“正确”,在viewDidUnload版本没有这个额外的版本,所以事情是仍然错误。

无论哪种方式,泄漏的引用离开NSFetchedResultsController活着。最终它发现一个变化,它试图发送给它的代表。而这当然是失败的,因为代表早已被释放。


机会很好,您从来不需要从该类的实现外部分配fetchedResultsController。你真正应该做的则是这样的:

酒店fetchedResultsController应该声明为:

@property (retain, readonly) NSFetchedResultsController *fetchedResultsController; 

您现有的fetchedResultsController是好的,但它应该分配_fetchedResultsController伊娃直接,而不是试图分配self.fetchedResultsController

随后的dealloc和viewDidUnload方法应该每个发行对象是这样的:

[_fetchedResultsController release]; 
_fetchedResultsController = nil; 

您还可以设置_fetchedResultsController.delegate零释放它,要格外肯定之前,但文档并不表示这是就像它为其他一些班级所做的那样。

+0

你是我的英雄。谢谢你的回复! – 2011-04-09 20:22:45

+0

亲爱的Anomie,我的应用程序出现类似的问题。你可以在这里检查我的代码,看看你是否注意到了什么?谢谢! http://stackoverflow.com/questions/5815549/getting-an-nsinvalidarguementexception-error – 2011-04-28 09:11:52

0

我有一个类似的问题,结果不同。

在我的情况下,我有一些KVO观察者在控制器中没有相应的removeObserver:forKeyPath:dealloc中的调用。

相关问题