objective-c - NSFetchedResultsController 保留对 Storyboard中已释放委托(delegate) Controller 的引用,导致崩溃

标签 objective-c memory-leaks ios5 nsfetchedresultscontroller uistoryboard

我有一个简单的 UIViewTable,在 Storyboard中使用 UINavigationController 推送 segue 实现了下钻细节。 有时,当我在详细 View 中时, TableView Controller 似乎被释放了,因此我得到了著名的:

[MyViewController controllerWillChangeContent:]: message sent to deallocated instance

我解释得更好,我有一个 NSOperation 队列,它异步加载我的数据,并在它刚完成时立即填充表。正确检索数据并填充表格。 对于详细 View ,我单击一个单元格并将 NSManagedObjectID 传递给 prepareForSegue 方法中的目标 Controller 。当我对详细 View 进行更改时,非常随机地获取的 Controller 松开了它的委托(delegate),或者看起来,作为 Controller 的委托(delegate)本身被释放了。导致崩溃。

获取的结果 Controller 被声明为一个属性:

@property(nonatomic,strong) NSFetchedResultsController *fetchedResultsController;

这就是从 viewDidLoad 开始的一切工作方式。

- (void)viewDidLoad {
    [super viewDidLoad];
    [self loadDataAsynchronously];
}

-(void)loadDataAsynchronously {

    NSOperationQueue *queue = [NSOperationQueue new];
    NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self
                                                                            selector:@selector(loadData)
                                                                              object:nil];

    [queue addOperation:operation];
}


-(void)loadData {

    NSFetchRequest *findAllEntities = [[NSFetchRequest alloc] init];
    [findAllEntities setEntity:ENTITY_DESC];

    NSSortDescriptor *sort = [[NSSortDescriptor alloc] initWithKey:@"created" ascending:YES];
    [findAllEntities setSortDescriptors:[NSArray arrayWithObject:sort]];
    [findAllEntities setFetchBatchSize:20];

    [NSFetchedResultsController deleteCacheWithName:@"MyCache"];
    if(self.fetchedResultsController==nil) {
        self.fetchedResultsController = [[NSFetchedResultsController alloc] 
                                            initWithFetchRequest:findAllPlants
                                            managedObjectContext:MOC
                                            sectionNameKeyPath:nil 
                                            cacheName:@"MyCache"];

        self.fetchedResultsController.delegate=self;
    }
    NSError *error=nil;
    if (![FRC performFetch:&error]) {
        exit(EXIT_FAILURE);
    }

    [self.dataTableView performSelectorOnMainThread:@selector(reloadData) withObject:nil waitUntilDone:YES];    

}

此代码有效,并且大部分时间也适用于被称为 segue 的详细 View :

-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {

    IP2SegueIdentifier segueIdentifier = [IP2Factory segueSolver:[segue identifier]];  
    MyDestinationViewController *dvc = [segue destinationViewController];
    NSIndexPath *indexPath = [TV indexPathForSelectedRow];
    dvc.entityID=[[self.fetchedResultsController objectAtIndexPath: indexPath] objectID];

}

目标 Controller 正确获取实体 ID 并通过询问上下文重建对象。 然后,当我在详细 View Controller 中时,我可以对实体进行更改,当我返回到导航层次结构时,我会进行上下文保存。 正是在这一点上,应用程序崩溃,就在上下文保存时。不是经常,而是时不时。 因为获取的结果 Controller 识别更改并提交给已经释放的委托(delegate)。

此时我几乎没有怀疑,我使用的是 iOS 5 和 ARC,因此编译器应该(几乎)完全控制 release 和 dealloc 方法。我还使用了一个带有简单导航层次结构的 Storyboard ,这应该保证保留整个以前的 View Controller 链。

我还运行了内存泄漏/僵尸分析的探查器,但没有发现任何错误,相反,我很高兴所有的对象管理都很好。

目前我没有太多猜测,所以请随时指出我可能忘记检查的地方,或者你在我的代码中看到的错误地方。

谢谢

最佳答案

首先,关于 ARC 的注释。虽然 ARC 提供自动归零 weak 指针,但它不会使 assign 指针自动归零。 NSFetchResultsController 为其委托(delegate)使用了一个assign 属性(参见NSFetchedResultsController.h):

@property(nonatomic, assign) id< NSFetchedResultsControllerDelegate > delegate;

在解除分配之前,您仍然有责任清除自己作为委托(delegate)人的身份。您通常在 dealloc 中执行此操作:

- (void)dealloc {
  _fetchedResultsController.delegate = nil;
}

您可能还想在 viewWillDisappear: 中删除您的 fetchedResultsController(包括删除您自己作为委托(delegate))。通常,当您不在屏幕上时,您不希望获取请求停留在周围。 (如果这样做,您可能应该在模型对象中而不是在 View Controller 中管理获取,因为 View Controller 可以在其 View 离开屏幕时随时消失。)

您的 loadData 很奇怪,因为它创建了一个 findAllEntities,但实际上使用了 findAllPlants。这是打字错误还是错误?如果在 ivar 中有一个单独的 findAllPlants 提取请求,这也可能是您出现问题的原因。

关于objective-c - NSFetchedResultsController 保留对 Storyboard中已释放委托(delegate) Controller 的引用,导致崩溃,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9215176/

相关文章:

objective-c - 如何使用 GPS 确定位置?

ios - 带有音频 AVAssetWriterInput "leaks"内存的 appendSampleBuffer 直到 endSessionAtSourceTime

javascript - 在tensorflow JavaScript中使用posenet时出现内存泄漏

iphone - 从ios中的另一个应用程序访问一个应用程序的文件

ios - 滚动时背景 alpha 过渡

ios - 在 ios 中使用 Collection View 创建 View

java - Glassfish/Hibernate 的 PermGen 空间问题

ios - 使用 GLKit 绘图

ios - 使用 NSURLConnection 上传时将进度设置为 UIProgressView

ios - 核心数据实体重命名