2011-10-24 11 views
12

申し訳ありませんが、ここで適切な言語はわかりませんが、デリゲートメソッドまたはオブザーバのターゲットとしてリストされた結果として呼び出されるメソッドのためにメソッドが呼び出されると、それらはメインスレッドで実行されます?iOSデリゲートとオブザーバーによって呼び出されたメソッドがメインスレッドで実行されていますか?

私は、これらの方法でUIの変更を行うことができ、または私は

dispatch_async(dispatch_get_main_queue(), ^{ UI stuff }); 

にTIAそれらをラップする必要がない場合、私は思ったんだけど:これは変えることができ、デリゲートのためにジョン・

答えて

9

を。ドキュメントで指定されていない場合は、通常、メインスレッドで送信されます。従来、UIKitはメインスレッドで使用する必要があり、そのため、これらのデリゲートはほとんどの場合メインスレッドから呼び出されます。

通知の場合この小さな切り札をしたいと思います。

通知センターは、オブザーバーに通知を同期的に配信します。言い換えれば、postNotification:メソッドは、すべてのオブザーバが通知を受信して​​処理するまで戻りません。通知を非同期に送信するには、NSNotificationQueueを使用します。 マルチスレッドアプリケーションでは、通知がポストされたスレッドで常に配信されます。オブザーバ自体が登録されている同じスレッドではない可能性があります。

http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/nsnotificationcenter_Class/Reference/Reference.html

から

そして最後にKVOのために、通知は、他のスレッドから来ることができます。アップルのエンジニアがそれらを処理することについて言わざるを得なかった点は次のとおりです。

http://lists.apple.com/archives/cocoa-dev/2007/May/msg00022.html

+0

またNSURLConnectionの場合、デリゲートコールバックは非同期ロード操作を開始したスレッドにありますが、これはメインスレッドである必要はありません。 – progrmr

+1

ドキュメントがこれを明確にしたなら、UIImagePickerControllerDelegate Protocol Referenceは 'thread'という単語を使用していないこともあります。私はimagePickerController:didFinishPickingMediaWithInfo:に問題は見られませんでしたが、私は突然スレッド問題を認識しています。あなたのスナップは間違いなく私のアプリで使用する通知に役立っていました。再び、私の新しいスレッド認識は私にそれらについて不思議に思った。私は彼らがすべて正しいことを確認するためにすべてを通過する必要があります。ありがとう! – John

+0

UIオブジェクトの場合、デリゲートは常にメインスレッド上にあると仮定できます。ドキュメントは、私が見たことがない例外があるかどうかを指定します。ここからドキュメントからこれを推測できます。 http://developer.apple.com/library/ios/documentation/uikit/reference/uiview_class/UIView/UIView.html#//apple_ref/doc/uid/TP40006816-CH3-SW147 – logancautrell

8

述べ、スレッドは、呼び出し元に基づいて変化するであろうように。あなたのデリゲートメソッドでは、あなたが適応する必要がある場合、あなたは常にこのような何か行うことができます。

if ([NSThread isMainThread]) { 
    // do the UI stuff as normal 
} else { 
    dispatch_async(dispatch_get_main_queue(), ^{ UI stuff }); 
} 
+0

現在のスレッドをチェックせずに常に非同期にディスパッチすると、どのような違いがありますか?したがって、たとえそのデリゲートメソッドがメインスレッドで呼び出されたとしても、私はディスパッチしますが、これの問題は何ですか?または、このソリューションの賛否両論(現在のスレッドをチェックする)は何ですか? –

+1

すでにメインスレッド上にあっても、dispatch_asyncを実行しても問題はないと思います。 dispatch_asyncメソッドのパフォーマンス上のペナルティが、NSThread isMainThreadプロパティをチェックするよりもそれほど悪くないことを確認するために、実験を行う必要があります。 –

3

を基本的な考え方は、(のために、すべての場合には、観察またはデリゲートメソッドが同じスレッドで呼び出されていることを最初の通知でありますオブザーバーパターン)または委任コードが実行されているかどうかわからない場合は、メインスレッドにUIブロックをディスパッチすることをお勧めします。私は以下の理由でこの陳述を正当化しようとします、もちろん私は間違っている可能性があります。

デリゲートプロトコルのドキュメントで明示的に指定されていない限り、デリゲートパターンでは、呼び出し元が呼び出しのときに実行しているのと同じスレッドでメソッドが直接呼び出されます。例えば。呼び出し側(委任オブジェクトは)彼のデリゲートを呼び出すために望んでおり、現在「スレッド-1」上で実行されている場合、その後の呼び出しは、同じスレッドで起こります:


// this is running in "Thread-1" --> then aDelegateMethod will continue on "Thread-1" 
[myDelegate aDelegateMethod] 

は限りオブザーバーパターンとして、私はしないでください主なスレッドで明示的に監視通知を送信する有効な理由を確認してください。特に、通知の元の値の変更が別のスレッドで実行されている場合は特に注意してください。実際にKVOの場合、ランタイムはクラス定義を変更して、通知を行うセッターメソッドをオーバーライドするいくつかのプライベートメソッドを追加します。この呼び出しをメインスレッドで明示的に行う有効な理由はありません。だから、私によれば、KVO通知は任意のスレッドから発生することができ、このスレッドは観測されたクラスの値の変更を実行しているスレッドと同じです。

NSNotificationCenterベースのメカニズムでは、元の通知がポストされた同じスレッドによって呼び出された通知が表示されます。これはAppleのドキュメントに明記されています(すべてのスレッドに独自の通知キューがあります)。

スレッドが維持されているので、UIブロックがメインキューで呼び出されていることを確認するには、質問に投稿したGCDコールを使用します。

+0

最後の文章を書き直してください:これは問題を処理する最も直接的な方法です。私はちょうど私のコードを通過し、私はすべての場合にこれを行うことを確認した。私のアプリは背景のスレッドでビデオを作成するので、私は問題に遭遇した。私はビデオが作成されている間、私のUI上のボタンを無効にしたいと思っていましたが、これはかすかな動作を引き起こしました。これはスレッドの問題の新たな認識を高めてくれました.-) – John

関連する問題