2011-11-22 2 views
6

データを含むテーブルをユーザーに表示しています。ビューが表示されるとすぐに、更新されたデータがあるかどうかを確認するためにWeb呼び出しを行います(非同期的に)。サービスコールが戻ると、私はコアデータとビューを更新したいと思います。CoreData:バックグラウンドで更新し、メインスレッドで読み取りによりデッドロックが発生する

ビューはサービス呼び出しと同じデータを読み込むため、残念ながらデッドロックが発生することがよくあります。これをどうすれば解決できますか?

私は、すぐにそれが凍結だとしてシミュレータを一時停止すると、待機中のスレッドは、次の場所で待っています

背景(更新)スレッド:(psynch_cvwait)

[mainContext performSelectorOnMainThread:@selector(mergeChangesFromContextDidSaveNotification:) 
           withObject:notification 
          waitUntilDone:YES]; 

メインスレッド:(psynch_mutexwait ) 実行中filteredArrayUsingPredicate

ありがとう!

+0

紹介文からMVCモデルを壊しているように感じました。データを制御し、それをフェッチするオブジェクトは1つだけでなければなりません。このビューは、モデルと交信しているコントローラーと会話する必要があります。 1つのオブジェクトだけが非同期呼び出しを行う場合、デッドロックは発生しません。それはとにかくちょうどちょうどちょっとです – simonpie

+0

私はそれを取得しない...私は1つのViewControllerがあります。ビューはこのコントローラにデータを要求します( 'filteredArrayUsingPredicate'を実行します)。同じViewControllerが、非同期Webサービス呼び出し(viewWillAppear)を開始します。この呼び出しは、戻り後にデータをデータベースに書き込みます。したがって、非同期呼び出しを行うオブジェクトは1つしかありませんが、それでもデッドロックが発生します。 – swalkner

+0

問題への実際の解決方法を見つけたことはありますか?私は似たような状況になりました(最終的に!)デバッガに閉じ込められましたが、ここからどこに行くのか分かりません... – elsurudo

答えて

8

-mergeChangesFromContextDidSaveNotification:は、メインスレッドをブロックします。この呼び出しでは、NSManagedObjectContextインスタンスがロックされ、変更内容がメインコンテキストに反映されます。

これは、一般にiOS 5以前のアプリケーションでは避けられないものとみなされます。より頻繁に、より小さな、節約することによってそれを最小化することができますが、それはまだ起こるでしょう。

iOS 5より前のアプリケーションで使用できる唯一のオプションは、メインコンテキストを-reset:にすることですが、すべてを再フェッチする必要があります。

+0

とiOS5アプリケーションで何ができるのでしょうか? – swalkner

+0

純粋なiOS 5.0アプリケーションの場合は、親子コンテキストを使用するとmergeChangesの必要性がなくなり、ブロック全体が削除されます。 –

+0

どのように機能しますか?この親/子コンテキスト処理に関するチュートリアル/ドキュメントがありますか? – swalkner

2

メインスレッドが、バックグラウンドスレッドがすでに持っている低レベルのロックを取得しようとしているようです(またはその逆)。あなたはどこかでmutexを提供するために@synchronizedを使用していますか?

とにかく、あなたのバックグラウンドスレッドが-mergeChangesFromContextDidSaveNotification:の完了を待つ必要がある理由はありますか?そうでない場合は、最後のパラメータとしてNOを渡します。

+0

私は '@synchronized'を使っていません...' -mergeChangesFromContextDidSaveNotification: '残念ながら、/ – swalkner

0

メインコンテキストとバックグラウンドコンテキスト(どちらもNSConfinementConcurrencyTypeを使用)の間でコンテキストの変更(両方向)をマージするとき、同じ問題(psynch_cvwaitでロック)が発生しました。ブロックが呼び出されていない、との両方のメインとバックグラウンドのキューが、私はそれを修正psynch_cvwait()

に掛けなかった結果

[[NSNotificationCenter defaultCenter] 
addObserverForName:NSManagedObjectContextDidSaveNotification 
object:mainContext 
queue:bgQueue 
usingBlock:^(NSNotification * _Nonnull note) { 
    // bgContext runs on bgQueue 
    [bgContext mergeChangesFromContextDidSaveNotification:note]; 
}] 

:問題は、それを送信した別のキューにNSManagedObjectContextDidSaveNotificationにサブスクライブすることによって引き起こされましたmainContextのキューをブロックしていないことで:

[[NSNotificationCenter defaultCenter] 
addObserverForName:NSManagedObjectContextDidSaveNotification 
object:mainContext 
queue:nil 
usingBlock:^(NSNotification * _Nonnull note) { 
    [bgQueue addOperationWithBlock:^{ 
     [bgContext mergeChangesFromContextDidSaveNotification:note]; 
    }]; 
}] 

しかし、メインのコンテキストに変更をマージするとき、私は、バックグラウンドキューをブロックする場合は、問題ではないようです。