NSDefaultRunLoopModeとNSRunLoopCommonModes


114

背後UIScrollViewにある大きなファイルなどをダウンロードしようとするMPMapViewと、iPhoneの画面に触れるとすぐにダウンロードプロセスが停止します。ありがたいことに、Jörnによる素晴らしいブログ投稿がNSRunLoopCommonModes、接続に使用する代替オプションを提案しています。

これにより、NSDefaultRunLoopModeとNSRunLoopCommonModesの2つのモードの詳細を調べることができますが、アップルのドキュメントでは、

NSDefaultRunLoopMode

NSConnectionオブジェクト以外の入力ソースを処理するモード。これは、最も一般的に使用される実行ループモードです。

NSRunLoopCommonModes

この値をモードとして使用して実行ループに追加されたオブジェクトは、「共通」モードのセットのメンバーとして宣言されているすべての実行ループモードによって監視されます。詳細については、CFRunLoopAddCommonModeの説明を参照してください。

CFRunLoopAddCommonMode

ソース、タイマー、オブザーバーは1つ以上の実行ループモードに登録され、実行ループがこれらのモードのいずれかで実行されている場合にのみ実行されます。共通モードは、これらのモードで共有されるソース、タイマー、オブザーバーのセットを定義できる実行ループモードのセットです。たとえば、特定の実行ループモードごとにソースを登録する代わりに、ソースを実行ループの共通疑似モードに一度登録すると、共通モードセットの各実行ループモードに自動的に登録されます。同様に、モードが共通モードのセットに追加されると、共通の疑似モードにすでに登録されているソース、タイマー、またはオブザーバーは、新しく追加された共通モードに追加されます。

誰かが人間の言語で2つを説明できますか?

回答:


204

実行ループは、システムがスリープ状態のスレッドを起動して非同期イベントを管理できるようにするメカニズムです。通常、スレッド(メインスレッドを除く)を実行する場合、実行ループでスレッドを開始するかどうかのオプションがあります。スレッドが外部イベントとの対話やタイマーなしでソートまたは長時間実行オペレーションを実行する場合、実行ループは必要ありませんが、スレッドが着信イベントに応答する必要がある場合は、実行ループにアタッチして、新しいイベントが到着したときにスレッドを起動します。これは、NSURLConnection(ネットワークからの)着信イベントでのみ起動するため、生成されたスレッドの場合です。

各スレッドは、複数の実行ループに関連付けることも、異なるモードで動作するように設定できる特定の実行ループに関連付けることもできます。「実行ループモード」は、特定のイベントを配信するか、後で配信するために収集するかについて、いくつかのルールを確立するためにOSによって使用される規則です。

通常、すべての実行ループは「デフォルトモード」に設定され、入力イベントを管理するデフォルトの方法を確立します。例:マウスドラッグ(Mac OS)またはタッチ(iOS)イベントが発生するとすぐに、この実行ループのモードはイベント追跡に設定されます。これは、スレッドが新しいネットワークイベントで起動されないことを意味しますが、これらのイベントは、後でユーザー入力イベントが終了し、実行ループが再びデフォルトモードに設定されたときに配信されます。これは明らかに、OSアーキテクトがバックグラウンドイベントではなくユーザーイベントを優先するために行った選択です。

NSURLConnectionを使用してスレッドの実行ループモードを変更する場合は、特定のデフォルトの実行ループではなくscheduleInRunLoop:forModes:、特別な実行ループモードにスレッドを割り当てることができます。呼び出される特別な疑似モードNSRunLoopCommonModesは、イベントトラッキングを含む多くの入力ソースで使用されます。たとえば、NSURLConnectionのインスタンスを共通モードに割り当てることは、そのイベントを「デフォルトモード」に加えて「トラッキングモード」に関連付けることを意味します。スレッドを関連付けることの1つの利点/欠点はNSRunLoopCommonModes、スレッドがタッチイベントによってブロックされないことです。

共通モードに新しいモードを追加できますが、これは非常に低レベルの操作です。

いくつかのメモを追加して終了します。

  • 通常、テーブルビューでネットワークからダウンロードした一連の画像またはサムネイルを使用する必要があります。テーブルビューのスクロール中にこれらの画像をネットワークからダウンロードすると、ユーザーエクスペリエンスが向上すると考えられます(スクロール中に画像を表示できるため)。スクロールの流動性が大幅に低下する可能性があるため、これは有利ではありません。この例ではNSURLConnection、実行ループは使用しないでください。UIScrollViewデリゲートメソッドを使用して、スクロールが終了したことを検出し、テーブルを更新してネットワークから新しいアイテムをダウンロードすることをお勧めします。

  • 実行ループ管理の問題からコードを「シールド」するのに役立つGCDの使用を検討してください。上記の例では、ネットワークリクエストをカスタムシリアルキューに追加することを検討できます。


9
Viggio24様この清潔で正確な説明をありがとうございました。AppleにAPIガイドへのコメントを含めるようお願いします。;)
Stkim1 2011

7
viggio24の答えは完璧です。興味のある方は、WWDC 2010のセッション208(iPhone OSのネットワークアプリ、パート2)に実行ループのイントロが含まれていることを指摘しておきます。興味のある方はご覧ください。それが役に立てば幸い。
ロレンゾB

19
自分へのメモ:のNSRunLoopCommonModesスクロール中にタイマーイベントを許可しUIScrollViewます。NSDefaultRunLoopModeスクロール中のタイマーを防止します。
eonil 2013

2
スクロールビューの更新についてのコメントは非常に興味深いものでした。これに関する詳細を追加するだけです:NSURLConnectionのモードを設定すると、これはデリゲートコールバックの実行にのみ影響します。ここでscrollViewを更新するとパフォーマンスの問題が発生する可能性があることを理解していますが、なぜこれが起こっているのですか?答えが画像をメモリにロードする必要がある場合は、背景のグラフィックコンテキストに書き込み、これを実行した後でビューのメインスレッドレイヤーを更新します。これは合理的に聞こえますか?
nebillo 14
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.