runloop

2021-11-16  本文已影响0人  QYCD
什么是runloop

顾名思义,runloop就是在"跑圈",本质是一个do-while循环。runloop提供了这么一个机制,当有任务处理时,线程的runloop会保持忙碌,而在没有任何任务处理时,会让线程休眠,从而让出CPU,当再次有任务需要处理时,runloop会被唤醒来处理事件,直到任务处理完毕,再次进入休眠。

runloop与线程

在viewDidLoad方法内(即在主线程中)添加这么一句

[self performSelector:@selector(testAction) withObject:nil afterDelay:2];

- (void)testAction {
    NSLog(@"==%d", [NSThread isMainThread]);
    NSLog(@"testAction");
}

执行后,2秒后打印:
==1
testAction

而如果在子线程中执行,则会发现2秒后并没有打印;performSelector:afterDelay:方法实质会创建一个定时器添加到runloop中,虽然每个线程都有一个runloop,但是只有主线程的runloop是开启的,而子线程的runloop需要我们自己run起来,定时器才会执行

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
         // 不执行
        [self performSelector:@selector(testAction) withObject:@3 afterDelay:2];
    });

修改为:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        [self performSelector:@selector(testAction) withObject:@3 afterDelay:2];
        [[NSRunLoop currentRunLoop] run];
    });
执行打印:
==0
testAction

app程序,函数入口main函数。
UIApplicationMain函数内部帮我们开启了主线程的runloop,内部拥有一个无限循环的代码,这样UIApplicationMain函数就不会立刻返回,只要程序不退出/崩溃,就一直循环。

#import <UIKit/UIKit.h>
#import "AppDelegate.h"

int main(int argc, char * argv[]) {
    NSString * appDelegateClassName;
    @autoreleasepool {
        // Setup code that might create autoreleased objects goes here.
        appDelegateClassName = NSStringFromClass([AppDelegate class]);
    }
    return UIApplicationMain(argc, argv, nil, appDelegateClassName);
}
runloop五种模式

一个 RunLoop 在某个 mode 下运行时,不会接收和处理其他 mode 的事件

应用场景

创建定时器的两种方式,在主线程,第一种方式会自动将定时器添加到当前runloop并且执行(run)的;第二种需要我们手动添加到当前runloop

// 方式1 默认将定时器添加到NSDefaultRunLoopMode模式
    NSTimer *timer1 = [NSTimer scheduledTimerWithTimeInterval:2 target:self selector:@selector(run) userInfo:nil repeats:YES];
    [timer1 fire]; //立即执行
    
    // 方式2
    NSTimer *timer2 = [NSTimer timerWithTimeInterval:2 target:self selector:@selector(run) userInfo:nil repeats:YES];
    [[NSRunLoop currentRunLoop] addTimer:timer2 forMode:NSDefaultRunLoopMode];
    [timer2 fire];

当页面滑动时当前runloop的mode从NSDefaultRunLoopMode切换到UITrackingRunLoopMode,此时原先的NSDefaultRunLoopMode事件将不再处理,不再滑动时再次切换会NSDefaultRunLoopMode后,定时器事件才继续执行;如果创建定时器时定义NSRunLoopCommonModes模式,则即使页面滑动也不会影响定时器事件的执行

iOS RunLoop总结

上一篇 下一篇

猜你喜欢

热点阅读