2011-08-02 9 views
3

ゲスト管理アプリケーションの開発でNSFe​​tchedResultsControllerの問題が発生しました。NSFetchedResultsControllerデリゲートとバックグラウンドでの更新の更新

基本的に、アプリケーションはバックグラウンドで(NSOperationサブクラスを使用して)ゲストリストをダウンロードし、管理対象オブジェクトコンテキストに挿入し、UIスレッドのテーブルビューで表示します。

コアデータのマルチスレッドルールに従っていると思います(スレッドで作成された操作のために別のMOCがあります。メインのMOCはdid-save通知などを使用して同期します)。

私が完全に理解していないのは、不正なUI更新を引き起こすメインスレッドではなく、バックグラウンドスレッドでデリゲートメソッド(controllerDidChangeContentなど)を呼び出すと思われるNSFetchedResultsControllerの動作です。

私の質問は - NSFetchedResultsControllerDelegateを使用してMOCの通知を保存するか、メインスレッドで行われた変更のみで動作するように設計されたNSFetchedResultsControllerDelegateを使用することは合法ですか?

私の説明が十分明確であるかどうかわからない場合は、問題を示すコードを投稿することができます。

答えて

2

私の推測では、MOC did-save通知がに送信され、メインイベントスレッドの代わりにバックグラウンドスレッドでが観測されたと思います。これにより、NSFetchedResultsControllerDelegateはバックグラウンドスレッドでデリゲートメッセージを送信します。あなたのセーブなかったことを確認する必要があり

通知オブザーバは例えば、メインスレッドに制御を渡します。

- (void)backgroundMOCDidSaveNotifiaction:(NSNotification *)notification 
{ 
    [uiMOC performSelectorOnMainThread: 
     @selector(mergeChangesFromContextDidSaveNotification:) 
    withObject:notification waitUntilDone:NO]; 
} 
+0

答えをいただきありがとうございました。私はあなたの解決策に終わった。私を混乱させたのは、Appleのドキュメントに関して、バックグラウンドスレッドからmergeChangesFromContextDidSaveNotificationを呼び出すことは合法です(このメソッドはスレッドセーフであるように設計されています)。だから、私は、Core Data自体が、どういうわけか、NSFetchedResultsControllerの正しいスレッドでの変更の受け渡しを魔法のように管理するだろうと考えました。 – Martin

+0

この点については、ドキュメントが混乱することに同意します。別のスレッドに通知を渡すことはできますが、スレッドセーフであるとは言えません。また、このメソッドを他のスレッドから呼び出すこともできますので、技術的に間違っているわけではありません。ドキュメントページにコメントを書くことをお勧めします:http://developer.apple.com/library/ios/#documentation/Cocoa/Reference/CoreDataFramework/Classes/NSManagedObjectContext_Class/NSManagedObjectContext.html –

0

免責

Daniel Dickison応答正しい答えです。これらのステップのいくつかは自明ではないので、ここではいくつかの詳細と説明だけを提供しています。

lazy var mainQueuemanagedObjectContext: NSManagedObjectContext = { 
    let coordinator = self.persistentStoreCoordinator 
    var managedObjectContext = NSManagedObjectContext(
     concurrencyType: .MainQueueConcurrencyType) 
    managedObjectContext.persistentStoreCoordinator = coordinator 
    return managedObjectContext 
    }() 

交通、ダウンロード、背景MOC:

lazy var transportManagedObjectContext:NSManagedObjectContext = { 
    let coordinator = CoreDataStack.sharedInstance.persistentStoreCoordinator 
    let managedObjectContext = NSManagedObjectContext(
     concurrencyType: .PrivateQueueConcurrencyType) 
    managedObjectContext.persistentStoreCoordinator = coordinator 
    return managedObjectContext 

    }() 

2つの異なる管理オブジェクトコンテキストの使用

UIスレッドMOCを行うには正しいことですバックグラウンド操作にはバックグラウンドMOCを使用してください。

transportManagedObjectContext.performBlockAndWait({() -> Void in 
    // ...add, change, delete objects, then save 
    try transportManagedObjectContext.save() 
}) 

Apple documentationによれば、バックグラウンド管理オブジェクトコンテキストにDaniel Dickisonの応答を適用します(このような新しいデータとしてダウンロードし、保存された):

// Broadcast NSManagedObjectContextDidSaveNotification 
NSNotificationCenter.defaultCenter().addObserver(
    self, 
    selector: "mocDidSaveNotification:", 
    name: NSManagedObjectContextDidSaveNotification, 
    object: self.transportManagedObjectContext) 

func mocDidSaveNotification(notification:NSNotification) 
{ 
    mainQueuemanagedObjectContext.performSelectorOnMainThread(
     "mergeChangesFromContextDidSaveNotification:", 
     withObject: notification, 
     waitUntilDone: true) 
} 

注:私は一般的に、が待っていないことを肯定的に知らない限り、performBlockAndWait()waitUntilDone: trueを使用することを好むは競合状態を引き起こしません。 でない場合は、を待つことを徹底的にお試しください。バックグラウンドスレッドがUIを待つように自由を取るが、は決しての逆である。

MainQueueConcurrencyType管理オブジェクトコンテキストを使用する必要があり、UIスレッド

NSFetchedResultsControllerから聞きます。

let fetchedResultsController = NSFetchedResultsController(
    fetchRequest: fetchRequest, 
    managedObjectContext: mainQueuemanagedObjectContext, 
    sectionNameKeyPath: "yourKey", 
    cacheName: nil) 

あなたNSFetchedResultsControllerは、バックグラウンド管理オブジェクトコンテキストから解放され、マージが完了したcontrollerWillChangeContentdidChangeObjectなどを受け取ることになります。

関連する問題