我有一个简单的UIViewTable,在故事板中使用UINavigationController push segue实现了深入细节。 它不时发生,表视图控制器似乎被解除分配,而我在详细视图中,因此我得到了着名的:
[MyViewController controllerWillChangeContent:]: message sent to deallocated instance
我解释得更好,我有一个NSOperation队列,它以异步方式加载我的数据,并在完成后立即填充表。正确检索数据并填充表格。 对于详细视图,我在prepareForSegue方法中单击一个单元格并将NSManagedObjectID传递给目标控制器。当我对详细信息视图进行更改时,非常随机,取出的控制器松开其委托,或者看起来,作为控制器的委托本身被取消分配。导致崩溃。
将获取的结果控制器声明为属性:
@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,如下所示:
-(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];
}
并且目标控制器正确获取实体id并通过询问上下文来重构对象。 然后,当我在详细视图控制器中时,我可以对实体进行更改,当我返回导航层次结构时,我会进行上下文保存。 正是在这一点上,应用程序崩溃,正好在上下文保存时。不是经常,但不时。 因为获取的结果控制器识别更改并提交给已取消分配的委托。
我现在几乎没有怀疑,我使用iOS 5和ARC,因此编译器应该(几乎)完全控制release和dealloc方法。我还使用了一个带有简单导航层次结构的故事板,它可以保证整个以前的视图控制器链得到保留。
我还运行探测器进行内存泄漏/僵尸分析,但无法发现任何错误,相反我很高兴所有对象管理都很好。
此时我没有多少猜测,所以请随意指出我可能忘记检查的内容,或者我在代码中看错的内容。
谢谢
答案 0 :(得分:21)
首先,关于ARC的说明。虽然ARC提供自动归零weak
指针,但它不会使assign
指针自动归零。 NSFetchResultsController
为其代理使用assign
属性(请参阅NSFetchedResultsController.h
):
@property(nonatomic, assign) id< NSFetchedResultsControllerDelegate > delegate;
在解除分配之前,您仍有责任将自己清除为代表。您通常在dealloc
:
- (void)dealloc {
_fetchedResultsController.delegate = nil;
}
您可能还想删除fetchedResultsController
中的viewWillDisappear:
(包括将自己移除为代理人)。通常,当您在屏幕外时,您不希望抓取请求保持不变。 (如果这样做,您可能应该管理模型对象而不是视图控制器中的提取,因为视图控制器可以在其视图在屏幕外的任何时候消失。)
您的loadData
很奇怪,因为它会创建findAllEntities
,但实际上会使用findAllPlants
。这是一个错字还是一个错误?如果在ivar中有单独的findAllPlants
获取请求,这也可能是您遇到问题的原因。