美文网首页
RunLoop 理解

RunLoop 理解

作者: bonoCat | 来源:发表于2017-08-01 20:33 被阅读34次

    Runloop解析

    概述

    do{
    
    }while (1)
    

    从字面的意思来看,就是运行循环,没有终点,一直运行。下面先看下大致 runloop 运行模式

    从官方图可以看出,在线程开始的时候就开始运行,知道某个时间点。运行的过程中,会有事件插入(port、custom、performSelector)、timer,这个时候runloop会提醒线程去处理相关的事,其他时间,线程处于休眠状态。

    相关类

    从图中可以看出一个 Runloop 包含多个 Mode

    typedef struct __CFRunLoopMode *CFRunLoopModeRef;
    

    有 5 种 mode

    KCFRunLoopDefaultMode // 默认 Mode
    UITrackingRunLoopMode // 保证页面滑动不受影响
    KCFRunLoopCommonModes  // 占位 Mode
    UIInitializationRunLoopMode // 刚启动时使用
    GSEventReceiveRunLoopMode   /// 系统事件内部Mode
    
    

    每种 mode 包含 一组 source、timer、observer

    typedef struct __CFRunLoopSource * CFRunLoopSourceRef;
    typedef struct __CFRunLoopObserver * CFRunLoopObserverRef;
    typedef struct __CFRunLoopTimer * CFRunLoopTimerRef;
    

    看下都有什么作用

    CFRunLoopTimerRef

    将定时器添加到指定 Mode ,在指定 Mode 下运行

    - (void)timer
    {
        NSTimer *timer = [[NSTimer alloc] initWithFireDate:[NSDate new] interval:1 repeats:YES block:^(NSTimer *timer) {
    
            NSLog(@"执行了%@", timer);
    
        }];
    
        [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
    }
    

    CFRunLoopSourceRef

    事件源:

    1.Port-Based Sources 从其他线程或内核发出
    2.custom Input Sources 自定义

    1. perform Selector Sources

    可以从函数调用栈来区分source 0 source 1

    • source 0 非Port(点击等)
    • source 1 基于Port
     UIButton *btn = [[UIButton alloc] initWithFrame:CGRectMake(0, 100, 100, 100)];
        btn.backgroundColor = [UIColor redColor];
        [btn addTarget:self action:@selector(btnClick) forControlEvents:UIControlEventTouchUpInside];
        [self.view addSubview:btn];
    
    
    栈调用关系.png

    从上面可以看出点击,是source 0 事件

    还有就是 perform Selector 的使用方式

    - (void)performSelector:(SEL)aSelector withObject:(nullable id)anArgument afterDelay:(NSTimeInterval)delay inModes:(NSArray<NSRunLoopMode> *)modes;
    

    就可以指定performSelector在某个Mode下运行

    CFRunLoopObserverRef

    runloop 状态监控

    /* Run Loop Observer Activities */
    typedef CF_OPTIONS(CFOptionFlags, CFRunLoopActivity) {
        kCFRunLoopEntry = (1UL << 0),   /// 即将进入RunLoop
        kCFRunLoopBeforeTimers = (1UL << 1), /// 即将处理 Timer
        kCFRunLoopBeforeSources = (1UL << 2), /// 即将处理 Sources
        kCFRunLoopBeforeWaiting = (1UL << 5), /// 即将进入休眠
        kCFRunLoopAfterWaiting = (1UL << 6), /// 从休眠中唤醒
        kCFRunLoopExit = (1UL << 7), /// 即将退出RunLoop
        kCFRunLoopAllActivities = 0x0FFFFFFFU /// 活跃中
    };
    

    通过对 RunLoop 监控,可以知道线程的状态,比如空闲时处理一些事情

     CFRunLoopObserverRef observer = CFRunLoopObserverCreateWithHandler(CFAllocatorGetDefault(), kCFRunLoopAfterWaiting, YES, 0, ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {
            
            
        });
        
        /*  不能主动创建 RunLoop
         CFRunLoopGetMain()
         CFRunLoopGetCurrent()
         */
        
        CFRunLoopAddObserver(CFRunLoopGetCurrent(), observer, kCFRunLoopDefaultMode);
    

    逻辑处理

    作用

    1.保证程序一直运行

    int main(int argc, char * argv[]) {
        @autoreleasepool {
            return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
        }
    }
    

    程序启动的时候,就会启动一个runloop,使得 main 函数不会有返回值。除非用户主动关闭,或者各种崩溃,或超时,也就是为什么我们app崩溃时候回进入 main 函数。

    /* Reasons for CFRunLoopRunInMode() to Return */
    enum {
        kCFRunLoopRunFinished = 1,
        kCFRunLoopRunStopped = 2,
        kCFRunLoopRunTimedOut = 3,
        kCFRunLoopRunHandledSource = 4
    };
    

    2.app各种事件处理(滑动、定时器、performSelector)

    3.节省cpu资源

    相关文章

      网友评论

          本文标题:RunLoop 理解

          本文链接:https://www.haomeiwen.com/subject/zcdslxtx.html