私のアプリケーションでは、ストレージに CoreData を使用し、NSFetchedResultsController を使用してデータを表示しています。
私は raywenderlich のチュートリアルに従ってそれを完成させました。それは大量のコードですが、一般的には適切に機能しています。必要に応じてその一部を投稿します。私は理解できない問題に固執しました。
NSFetchedResultsController と組み合わせた UITableView 内に表示されるデータは、バックグラウンドで更新できます-ここで私の問題が始まりました。
Pull-to-refresh アプローチを行っており、別のスレッドでバックグラウンドでダウンロードを開始しています。このスレッド用に作成された独自の NSManagedObjectContext を使用し、すべてのオブジェクトが作成された後に保存します。
コードは次のとおりです。
- (void)refresh:(id)sender
{
[ServerConnection downloadContactsForToken:token success:^(NSDictionary* responseObject)
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSManagedObjectContext* context = [[[AppManager sharedAppManager] createManagedObjectContext] retain];
NSArray* responseContacts = responseObject[@"contacts"];
[responseContacts enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
//ContactDB is NSManagedObject
[[[ContactDB alloc] initWithDictionary:obj andContext:context] autorelease];
}];
[context save:nil];
[context release];
dispatch_async(dispatch_get_main_queue(), ^{
[self.refreshControl endRefreshing];
});
});
}];
}
Apple docs で読んだことによると、メインスレッド NSManagedObjectContext でこれらの変更を検出する適切な方法は次のとおりです。
- (void) viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(managedObjectContextDidSave:)
name:NSManagedObjectContextDidSaveNotification
object:nil];
}
- (void)managedObjectContextDidSave:(NSNotification *)notification {
dispatch_async(dispatch_get_main_queue(), ^{
if(notification.object != [[AppManager sharedAppManager] managedObjectContext]) {
[[[AppManager sharedAppManager] managedObjectContext] mergeChangesFromContextDidSaveNotification:notification];
}
});
}
基本的に、managedObjectContext の変更に関する通知を受け取ると、変更をメイン スレッド コンテキストにマージします。そして、それは一般的に機能しますが、プロファイリングを開始した後、記述されたプロセスにマージされたすべてのオブジェクトが決して割り当て解除されないことを発見しました.
メインスレッドですべてを行うと、動作します-UITableViewをスクロールすると、期待どおりに割り当てが解除されます。
回避策を見つけたので、電話しています:
[[[AppManager sharedAppManager] managedObjectContext] reset];
マージが完了したら:
[[[AppManager sharedAppManager] managedObjectContext] mergeChangesFromContextDidSaveNotification:notification];
[[[AppManager sharedAppManager] managedObjectContext] reset];
しかし、なぜそれをしなければならないのか、それが他の何かを壊すのかどうかはわかりません. バックグラウンドでデータを更新するより良い方法があるかもしれませんが、私は完全に間違った方向に進んでいます。