无法在 dealloc 中释放 NSFetchedResultsController

Posted

技术标签:

【中文标题】无法在 dealloc 中释放 NSFetchedResultsController【英文标题】:Can't Release NSFetchedResultsController in dealloc 【发布时间】:2010-10-25 02:50:49 【问题描述】:

我有两个 UITableViewControllers 具有相当简单的 ui 流程。当您在第一个 UITableViewController 中选择一个项目时,一个 UITableViewController 会加载另一个 UITableViewController。


(UITableViewController) 故事列表 -> 选择一个故事 -> (UITableViewController) 句子列表


在第二个 UITableViewController (MakeSentenceDetailViewController) 中,我无法释放我的 NSFetchedResultsController 而不会导致错误(显示为 Zombies 设置为 on):

-[NSFetchRequest release]:消息发送到释放的实例0x5b370f0

NSFetchedResultsController 的保留计数保持在 1,但是当我尝试在 dealloc 中释放它时,我遇到了崩溃。

代码,尤其是关于 NSFetchedResultsController 的代码在两个表视图中是相同的,但是在 MakeSentenceDetailViewController 中,我无法在崩溃时释放这个 NSFetchedResults 控制器 - 给我一个泄漏。

如何安全地释放我的 NSFetchedResultsController?为什么它在父(第一个)tableviewcontroller 中工作正常 - 但在第二个中却不行?

我可以为第一个 UITableViewController 提供代码,但关于 NSFetchedResultsController 它的声明和使用方式几乎相同。

MakeSentenceTableViewController.h:

@interface MakeSentenceTableViewController : UITableViewController 
NSManagedObjectContext  *managedObjectContext;  
NSFetchedResultsController *fetchedResultsController;

@property (nonatomic, retain)  Story *story;
@property (nonatomic, retain) NSManagedObjectContext *managedObjectContext;
@end

MakeSentenceTableViewController.m(与 NSFetchedResultsController 相关的代码):

 - (void)viewDidLoad 
 [super viewDidLoad];
 if (managedObjectContext == nil) 
  
 managedObjectContext = [(MyAppAppDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext];
 NSLog(@"After managedObjectContext: %@",  managedObjectContext);
 
   NSFetchRequest *request = [[[NSFetchRequest alloc] init] autorelease];
  NSEntityDescription *entity = [NSEntityDescription entityForName:@"Sentence" inManagedObjectContext:managedObjectContext];
  [request setEntity:entity];
  //sorting stuff:
  NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"order" ascending: YES];
  NSArray *sortDescriptors = [[NSArray alloc] initWithObjects: sortDescriptor, nil];
  [request setSortDescriptors:sortDescriptors];
  //[request setFetchBatchSize:FETCH_BATCH_SIZE];
  [sortDescriptors release];
  [sortDescriptor release];
  fetchedResultsController = [[NSFetchedResultsController alloc] 
    initWithFetchRequest:request managedObjectContext:managedObjectContext 
    sectionNameKeyPath:nil cacheName:nil];
  [request release];
  NSError *error;
  [fetchedResultsController performFetch:&error];
  NSLog(@"FetchedResultsController: %@", fetchedResultsController);
  NSLog(@"fetchedResultsController RetainCount at viewDidLoad: %d", [fetchedResultsController retainCount]);
 

 - (void)dealloc 

  //Gotta figure out why I can't release this:
  [fetchedResultsController release]; //Crash! Burn! 
  NSLog(@"fetchedResultsController RetainCount at dealloc: %d", [fetchedResultsController retainCount]);
  [managedObjectContext release];
  [super dealloc];
 

【问题讨论】:

【参考方案1】:
NSFetchRequest *request = [[[NSFetchRequest alloc] init] autorelease];
// ...snip...
[request release];

您正在释放一个已放弃所有权的对象(使用-autorelease)。因为 NSFetchedResultsController 也保留了获取请求,所以在其他版本时您不会收到错误;因此,当控制器释放对获取请求的最后一个引用时,实际上是导致崩溃的控制器。

【讨论】:

谢谢你 - 这解决了问题,但它也创造(或揭示)另一个问题。现在每三次(如发条)我进入 MakeSentenceViewController(使用导航控制器在 TableViewController 之间切换)我在这行代码上崩溃: managedObjectContext = [(MyAppAppDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext];你能看出任何明显的联系吗?它超出了这个问题的范围。 取决于它到底是如何崩溃的。 好吧,我会在接下来的一周左右进行一些额外的调试 - 如果找到解决方案,请在此处发布解决方案,如果找不到,我将创建一个新问题。非常感谢您抽出宝贵时间。【参考方案2】:

你过度释放了 NSFetchRequest

你在这里自动释放它:

   NSFetchRequest *request = [[[NSFetchRequest alloc] init] autorelease];

稍后再发布:

  [request release];

然后当您释放 fetchedResultsController 时,它会再次尝试释放相同的请求。

【讨论】:

以上是关于无法在 dealloc 中释放 NSFetchedResultsController的主要内容,如果未能解决你的问题,请参考以下文章

Oracle—deallocate unused释放高水位空间

如何在 -dealloc 中正确释放 CGMutablePathRef?

我应该在 dealloc 中释放实例变量和属性吗?

有必要在dealloc中释放这个对象吗?

UIViewController 在 dealloc 时不释放子视图(使用 ARC)

iOS Objective-C dealloc方法释放的是啥?