120

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

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

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

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

4

5 に答える 5

224

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

各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

于 2012-08-23T13:00:33.323 に答える
16

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

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

ここから

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

このコメントからも:

バックグラウンドスレッドには独自の実行ループはありませんが、追加するだけです。たとえば、AFNetworking2.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.current異なる値を返すのか考えているかもしれません。共有価値ではないですか!?素晴らしい質問です!さらに読む:

重要な注意点:

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

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

それは文脈的です。スレッドのスコープ内、つまりスレッドローカルストレージ内でのみ表示されます。詳細については、こちらをご覧ください

これはタイマーの既知の問題です。使用する場合、同じ問題は発生しませんDispatchSourceTimer

于 2017-08-04T20:25:09.953 に答える
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に設定するまで実行されます。

同様に、スレッドでそれらを使用できます。

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

于 2014-10-14T09:30:54.617 に答える
1

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

ここから


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

ここから

于 2018-04-25T01:50:26.953 に答える
0
Swift
let runLoop = RunLoop.current

Obj-c
NSRunLoop * runloop = [NSRunLoop currentRunLoop];

実行ループは、入力イベントを継続的に監視および処理し、それらを対応するターゲットに割り当てて処理するために使用されるイベント処理ループです。

于 2021-07-20T01:55:18.467 に答える