ストーリーボードのUINavigationControllerプッシュセグエで実現されたドリルダウンの詳細を備えた単純なUIViewTableがあります。詳細ビューを表示しているときに、テーブルビューコントローラーの割り当てが解除されているように見えることがあります。そのため、有名なものが表示されます。
[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];
}
このコードは機能し、ほとんどの場合、次のようなセグエと呼ばれる詳細ビュー内でも機能します。
-(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を正しく取得し、コンテキストを尋ねることによってオブジェクトを再構築します。次に、詳細ビューコントローラにいるときにエンティティに変更を加えることができ、ナビゲーション階層に戻るときにコンテキスト保存を実行します。この時点で、コンテキストの保存時にアプリケーションがクラッシュします。それほど頻繁ではありませんが、時々です。フェッチされた結果コントローラーは変更を認識し、既に割り当てが解除されているデリゲートに送信されるためです。
この時点で私はほとんど疑問を持っていません。私はiOS5とARCを使用しているので、コンパイラーはリリースとdeallocメソッドを(ほぼ)完全に制御できるはずです。また、単純なナビゲーション階層を備えたストーリーボードを使用しています。これにより、以前のViewControllerチェーン全体が保持されることが保証されます。
また、メモリリーク/ゾンビ分析のためにプロファイラーを実行しましたが、何も問題を見つけることができませんでした。それどころか、すべてのオブジェクト管理が正常であったことを嬉しく思いました。
現時点では推測が少ないので、確認し忘れた可能性のあるものや、コードに誤りがあると思われるものをお気軽にご指摘ください。
ありがとう