Runloopアプリケーションの詳しい説明

序文

Runloop は、iOS のスレッドに適用されるループ メカニズムです。システム自体には実行ループを作成するための API はありませんが、現在の RunLoop は currentRunLoop を通じて取得できます。メインスレッド自体は runloop を持っており実行状態ですが、サブスレッドの runLoop を手動で開かないと入力ソースやタイミングソースを監視できません。子スレッド RunLoop は、子スレッドのイベント ソースが終了すると閉じられ、子スレッドが終了すると解放されます。

RunLoopオブジェクトの取得/作成    

[NSRunLoop currentRunLoop];//当前线程的runLoop

[NSRunLoop mainRunLoop];//主线程runLoop

CFRunLoopGetCurrent();

CFRunLoopGetMain();

[NSRunLoop currentRunLoop].getCFRunLoop; //NSRunLoop转CFRunLoopRef

 NSRunLoop オブジェクトはスレッド セーフではありません。同じ runLoop オブジェクトを異なるスレッドで使用する場合は、CFRunLoopRef を使用してスレッド セーフを確保できます。

タイマーと入力ソースを追加する 

[[NSRunLoop currentRunLoop] addTimer:<#(nonnull NSTimer *)#> forMode:<#(nonnull NSRunLoopMode)#>]

[[NSRunLoop currentRunLoop] addPort:<#(nonnull NSPort *)#> forMode:<#(nonnull NSRunLoopMode)#>]

CFRunLoopAddTimer(<#CFRunLoopRef rl#>, <#CFRunLoopTimerRef timer#>, <#CFRunLoopMode mode#>)

CFRunLoopAddSource(<#CFRunLoopRef rl#>, <#CFRunLoopSourceRef source#>, <#CFRunLoopMode mode#>)

RunLoopを開始する

[[NSRunLoop currentRunLoop] run]; //无条件且以默认的NSDefaultRunLoopMode启动

[[NSRunLoop currentRunLoop] runUntilDate:[NSDate new]]; //指定过期时间且以默认的NSDefaultRunLoopMode启动

[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate new]];//指定过期时间,指定启动方式

CFRunLoopRun(); //子线程的runLoop需要启动

CFRunLoopRunInMode(<#CFRunLoopMode mode#>, <#CFTimeInterval seconds#>, <#Boolean returnAfterSourceHandled#>)

RunLoop を終了する

/* 给RunLoop设置超时时间 */
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate new]]; //指定过期时间且以默认的NSDefaultRunLoopMode启动

[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate new]];//指定过期时间,指定启动方式

/* 通知RunLoop停止  */
CFRunLoopStop([NSRunLoop currentRunLoop].getCFRunLoop); 

子スレッドの RunLoop はイベント ソースの終了とともに終了するため、通常、RunLoop はアクティブに停止されません。

メインスレッドのシナリオ    

NSTimer *timer = [NSTimer timerWithTimeInterval:1.0 target:self selector:@selector(fireDemo) userInfo:nil repeats:YES];

タイマーは直接使用でき、デフォルトは NSDefaultRunLoopMode です。

[[NSRunLoop mainRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];

UIScrollViewをスライドさせるとRunLoopはUITrackingRunLoopModeモードに切り替わりますが、NSDefaultRunLoopModeのデフォルトのTimerは呼び出されなくなりますが、NSRunLoopCommonModesに設定することで通常に戻すことができます。

サブスレッドのシナリオ

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    NSTimer *timer = [NSTimer timerWithTimeInterval:1.0 target:self selector:@selector(timerCount) userInfo:nil repeats:NO];
       
    [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode]; //添加timer,使用默认runloop模式
     
    [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
    //timer结束后,触发breakPoint
});

子スレッドは RunLoop コードを開始します。runLoop が開始されると、runMode 以降のコードは実行されません。runMode 以降のコードは、Timer が終了して RunLoop が終了するまで実行されません。タイマーの繰り返しが YES の場合、runMode 以降のコードは実行されます;子スレッド RunLoop には UITrackingRunLoopMode モードがありません。

//开启子线程runloop时必须添加相应的timer或port,否知运行无效
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate distantFuture]]; 
[[NSRunLoop currentRunLoop] run]; 
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    NSTimer *timer = [NSTimer timerWithTimeInterval:1.0 target:self selector:@selector(timerCount) userInfo:nil repeats:NO];
       
    [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
     
    [[NSRunLoop currentRunLoop] run];
    //timer结束后,没有触发breakPoint
});

[currentRunLoop run] メソッドを呼び出してサブスレッドの実行ループを開始すると、停止することはできません。実行がブロックされた後、コードが実行され、サブスレッドは解放されません。

[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:3.0]];

//do something

  コードは実行後にブロックされ、runLoop が終了するまで実行されません。

常駐サブスレッドを作成する

+ (NSThread *)networkThread {
    static dispatch_once_t onceToken;
    static NSThread *_networkThread;
    dispatch_once(&onceToken, ^{
        _networkThread = [[NSThread alloc] initWithTarget:[[self class] sharedInstance] selector:@selector(_runLoopThread) object:nil];
        [_networkThread setName:@"com.network.request"];
        [_networkThread setQualityOfService:[[NSThread mainThread] qualityOfService]];
        [_networkThread start];
    });

    return _networkThread;
}

- (void)_runLoopThread {
    // 直接使用run比较暴力,无法手动销毁线程
    [[NSRunLoop currentRunLoop] addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode];
    [runLoop run]; 

    /* 另一种形式
    [[NSRunLoop currentRunLoop] addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode];
    while (!_stopRunning) {
        @autoreleasepool {
            [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
        }
    }
    */
}

コードはブロックするがスレッドはブロックしない

 __block BOOL isContinue = NO;

 dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
    isContinue = YES;
 });

 while (isContinue == NO) {
    [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
 }
//isContinue为YES后执行后续代码

実際のプロジェクトでは、このメソッドは、スレッド操作をブロックせずにブロック コードを実装するためにメイン スレッドでよく使用されます。たとえば、非同期操作が完了するのを待ってから後続のコード ブロックを呼び出します。

おすすめ

転載: blog.csdn.net/z119901214/article/details/82260795