スレッド間で NSManagedObjectContext を使い回すのはダメらしい

iPad アプリを作ってたら、エラーとともに、良くわからないメッセージ (T^T)

Not safe to look up objc runtime data.

試しに上記メッセージで検索すると、スレッドに関係するっぽい FAQ が見つかる。


エラーは NSManagedObjectContext save の実行タイミングで発生してるけど、毎回ってわけじゃない。しかも非同期通信やってて別スレッドが save を呼び出してるから、スレッドセーフじゃないってのは容易に推測できる。^^;)

そー思いながら、調べてたら、こんな記述を Apple Core Data Programming Guide で見つけた。

管理対象オブジェクトコンテキストをロックした場合(すなわち、正常に tryLock できた場合)は、ロック解除を呼び出すまで、ロックを発動したスレッドでコンテキストを保持きるようにする必要があります。マルチスレッド環境でコンテキストを適切に保持しないと、デッドロックが発生します。

管理対象オブジェクトの使用 メモリ管理


さらに検索してたら Core Data multi thread applicationApple Document に注意書きあるよーって記述みつけた。思い切り、スレッド間で NSManagedObjectContext を使い回す実装してました。すんません。 ^^;)>

Basic rules are:

1. Use one NSPersistentStoreCoordinator per program. You don't need them per thread.
2. Create one NSManagedObjectContext per thread.
3. Never pass an NSManagedObject on a thread to the other thread.
4. Instead, get the object IDs via -objectID and pass it to the other thread.
 
More rules:

1. Make sure you save the object into the store before getting the object ID. Until saved, they're temporary, and you can't access them from another thread.
2. And beware of the merge policies if you make changes to the managed objects from more than one thread.
3. NSManagedObjectContext's -mergeChangesFromContextDidSaveNotification: is helpful.

Core Data multi thread application


どーやって実装すれば良いかなーと思ってたら、こちらが参考になりそう。


直接メッセージには触れてないけど、NSManagedObjectContext はスレッド毎に管理しましょーとなっているところを見ると、同じようなケースにハマったんだろね。

参考にさせてもらいまする :-)

追記 9/22

他にもこんなの見つけた。stack over flow にあった Q&A で、ぼくの考えた方法(1)でどうよ?というのに対して(2)の方がいいんじゃね?というアドバイスが飛んでる。まだ良く読めてないけど、こちらも参考になりそうなのでメモっとこ。:-)