NSRunLoopについて


108

誰かが何について説明できますNSRunLoopか?私が知っNSRunLoopているように、何かが関連していNSThreadますか?だから私はのようなスレッドを作成すると仮定します

NSThread* th=[[NSThread alloc] initWithTarget:self selector:@selector(someMethod) object:nil];
[th start];

-(void) someMethod
{
    NSLog(@"operation");
}

それで、このスレッドが彼の右の仕事を終えた後?なぜ使用するのRunLoopsか、どこで使用するのか?Apple docsから何か読んだことがありますが、はっきりしていませんので、できるだけ簡単に説明してください


この質問は範囲が広すぎます。質問をより具体的なものに絞り込んでください。
ジョディヘイギンズ

3
最初に、一般的なNSRunLoopで何が行われ、それがどのようにスレッドと接続されているのかを知りたい
taffarel

回答:


211

実行ループは、(とりわけ)システム入力ソース(ソケット、ポート、ファイル、キーボード、マウス、タイマーなど)を処理するメカニズムを提供する抽象化です。

各NSThreadには独自の実行ループがあり、currentRunLoopメソッドを介してアクセスできます。

一般に、実行ループに直接アクセスする必要はありませんが、I / O処理に使用する実行ループを指定できる(ネットワーク)コンポーネントがいくつかあります。

特定のスレッドの実行ループは、その1つ以上の入力ソースにデータまたはイベントがあるまで待機してから、適切な入力ハンドラを起動して、「準備完了」の各入力ソースを処理します。

その後、ループに戻り、さまざまなソースからの入力を処理し、実行する作業がない場合は「スリープ」します。

これはかなり高レベルの説明です(詳細が多すぎないようにします)。

編集

コメントに対処する試み。私はそれをバラバラにしました。

  • これは、スレッド内でループを実行するためにのみアクセス/実行できることを意味しますか?

確かに。NSRunLoopはスレッドセーフではないため、ループを実行しているスレッドのコンテキストからのみアクセスする必要があります。

  • ループを実行するイベントを追加する簡単な例はありますか?

ポートを監視する場合は、そのポートを実行ループに追加するだけで、実行ループはそのポートのアクティビティを監視します。

- (void)addPort:(NSPort *)aPort forMode:(NSString *)mode

タイマーを明示的に追加することもできます

- (void)addTimer:(NSTimer *)aTimer forMode:(NSString *)mode
  • その後、ループに戻りますか?

実行ループは、(モードに応じて)反復ごとにすべての準備完了イベントを処理します。一般的な答えの範囲を少し超えているので、実行モードについて見つけるためにドキュメントを見る必要があります。

  • スレッドを開始すると、実行ループは非アクティブですか?

ほとんどのアプリケーションでは、メインの実行ループが自動的に実行されます。ただし、実行ループを開始し、スピンするスレッドの着信イベントに応答する必要があります。

  • スレッド外のスレッド実行ループにいくつかのイベントを追加することは可能ですか?

ここで何を言っているのかわかりません。実行ループにイベントを追加しません。入力ソースとタイマーソースを追加します(実行ループを所有するスレッドから)。次に、実行ループがアクティビティを監視します。もちろん、他のスレッドやプロセスからのデータ入力を提供することもできますが、入力は、実行ループを実行しているスレッド上のそれらのソースを監視している実行ループによって処理されます。

  • 実行ループを使用して一時的にスレッドをブロックできるという意味ですか

確かに。実際、実行ループは、イベントハンドラーが戻るまで、イベントハンドラー内にとどまります。これはどのアプリでも十分簡単に​​見ることができます。スリープするIOアクション(ボタンを押すなど)のハンドラーをインストールします。そのメソッドが完了するまで、メインの実行ループ(およびUI全体)をブロックします。

同じことがどの実行ループにも当てはまります。

実行ループに関する次のドキュメントを読むことをお勧めします。

https://developer.apple.com/documentation/foundation/nsrunloop

スレッド内での使用方法:

https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/Multithreading/RunLoopManagement/RunLoopManagement.html#//apple_ref/doc/uid/10000057i-CH16-SW1


2
これは、スレッド内でループを実行するためにのみアクセス/実行できることを意味しますか?ループを実行するイベントを追加する簡単な例はありますか?その後、ループに戻りますか?スレッドを開始すると、実行ループは非アクティブですか?スレッド外のスレッド実行ループにいくつかのイベントを追加することは可能ですか?それは時々実行ループを使用して一時的にスレッドをブロックできることを意味しますか?
タファレル2012

「スリープしているIOアクション(ボタンを押すなど)のハンドラーをインストールします。」ボタンを指で押し続けると、しばらくの間スレッドがブロックされ続けますか?
Honey

いいえ。つまり、ハンドラが完了するまで、runloopは新しいイベントを処理しないということです。ハンドラーでスリープ状態(または時間がかかる操作)を実行すると、ハンドラーが処理を完了するまで実行ループがブロックされます。
ジョディヘイギンズ

@taffarel スレッドの外側のスレッド実行ループにいくつかのイベントを追加することは可能ですか?それが「別のスレッドのrunloopで自由にコードを実行できるようにすること」を意味する場合、答えは確かにyesです。を呼び出すだけでperformSelector:onThread:withObject:waitUntilDone:NSThreadオブジェクトを渡し、セレクターはそのスレッドの実行ループでスケジュールされます。
メッキ

12

実行ループは、インタラクティブアプリをコマンドラインツールから分離 するものです 。

  • コマンドラインツールはパラメーターを指定して起動され、コマンドを実行して終了します。
  • インタラクティブアプリは、ユーザーの入力を待ち、反応してから、待機を再開します。

ここから

それらは、ユーザーがタップしてそれに応じて応答するまで待機し、completementHandlerを取得してその結果を適用するまで待機し、タイマーを取得して関数を実行するまで待機します。実行ループがない場合は、ユーザーのタップをリッスン/待機することはできません。ネットワークコールが発生するまで待つことはできません。DispatchSourceTimerまたは、DispatchWorkItem

また、このコメントから:

バックグラウンドスレッドには独自の実行ループはありませんが、追加することができます。たとえば、AFNetworking 2.xはそれを行いました。これは、バックグラウンドスレッドでのNSURLConnectionまたはNSTimerに対して真の手法で試行されましたが、新しいAPIを使用する必要がなくなるため、これ以上自分で行うことはありません。しかし、URLSessionは、たとえば、ここでは単純なリクエストであり、メインキューで[画像の左側のパネルを参照]完了ハンドラーを実行しているように見え、バックグラウンドスレッドに実行ループがあることがわかります。


具体的には、「バックグラウンドスレッドには独自の実行ループはありません」。次のタイマーは、非同期ディスパッチの起動に失敗します。

class T {
    var timer: Timer?

    func fireWithoutAnyQueue() {
        timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: false, block: { _ in
            print("without any queue") // success. It's being ran on main thread, since playgrounds begin running from main thread
        })
    }

    func fireFromQueueAsnyc() {
        let queue = DispatchQueue(label: "whatever")
        queue.async {
            self.timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: false, block: { (_) in
                print("from a queue — async") // failed to print
            })
        }
    }

    func fireFromQueueSnyc() {
        let queue = DispatchQueue(label: "whatever")
        queue.sync {
            timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: false, block: { (_) in
                print("from a queue — sync") // success. Weird. Read my possible explanation below
            })
        }
    }

    func fireFromMain() {
        DispatchQueue.main.async {
            self.timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: false, block: { (_) in
                print("from main queue — sync") //success
            })
        }
    }
}

私が理由だと思うsyncブロックも実行している理由は次のとおりです。

同期ブロックは通常、ソースキュー内から実行されます。この例では、ソースキューがメインキューで、どのキューも宛先キューです。

テストするために、RunLoop.currentすべてのディスパッチにログインしました。

同期ディスパッチには、メインキューと同じ runloopがありました。一方、非同期ブロック内のRunLoopは、他のインスタンスとは異なるインスタンスでした。なぜRunLoop.current別の値が返されるのかを考えているかもしれません。共有価値じゃないですか!?すばらしい質問です。さらに読む:

重要な注意点:

クラスプロパティは、 currentグローバル変数ではありません。

現在のスレッドの実行ループを返します。

それは状況に応じたものです。これは、スレッドのスコープ内、つまりThread-local storage内でのみ表示されます。詳しくはこちらをご覧ください

これはタイマーの既知の問題です。あなたが使用する場合、あなたは同じ問題を抱えていませんDispatchSourceTimer


8

RunLoopsは、何かが発生する箱のようなものです。

基本的に、RunLoopでは、いくつかのイベントを処理してから戻ります。または、タイムアウトになる前にイベントを処理しない場合は戻ります。非同期のNSURLConnectionsと同様に、現在のループを妨害することなくバックグラウンドでデータを処理すると同時に、同期的にデータが必要です。これは、非同期NSURLConnectionにして、呼び出し時にデータを提供するRunLoopの助けを借りて行うことができます。次のようにRunLoopを使用できます。

NSDate *loopUntil = [NSDate dateWithTimeIntervalSinceNow:0.1];

while (YourBoolFlag && [[NSRunLoop currentRunLoop] runMode: NSDefaultRunLoopMode beforeDate:loopUntil]) {
    loopUntil = [NSDate dateWithTimeIntervalSinceNow:0.1];
}

このRunLoopでは、他の作業が完了してYourBoolFlagfalseに設定されるまで実行されます

同様に、スレッドで使用できます。

これがお役に立てば幸いです。


0

実行ループは、スレッドに関連する基本的なインフラストラクチャの一部です。実行ループは、作業をスケジュールし、着信イベントの受信を調整するために使用するイベント処理ループです。実行ループの目的は、実行する作業があるときにスレッドをビジー状態に保ち、実行する作業がないときにスレッドをスリープ状態にすることです。

ここから


CFRunLoopの最も重要な機能はCFRunLoopModesです。CFRunLoopは、「Run Loop Sources」のシステムで動作します。ソースは、1つまたは複数のモードの実行ループに登録され、実行ループ自体が特定のモードで実行されます。イベントがソースに到着すると、ソースモードが実行ループの現在のモードと一致する場合にのみ、実行ループによって処理されます。

ここから

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.