iOS RunLoop

作者: 山有木枝壮 | 来源:发表于2019-07-04 11:56 被阅读0次

    RunLoop总结

    1、每个应用都会有一个主线程,主线程对应一个runloop,保证应用一直在运行
    2、default模式的RunLoop是同通过do…while循环实现的
    3、获取RunLopp对象,NSRunLoop是基于NSRunLoopRef的封装
    [NSRunLoop currentRunLoop]; // 获得当前线程的RunLoop对象
    [NSRunLoop mainRunLoop]; // 获得主线程的RunLoop对象
    4、每一个Thread都对应一个RunLoop,主线程的RunLoop会在创建的时候自动创建,并且会保存在Dictionary中,线程的指针会作为key,RunLoop作为对应的value。
    子线程中使用currentRunLoop会获取子线程对应的RunLoop对象,如果没有,系统会自动创建,并且保存在全局的Dictionary中。如果不获取,不会自动创建
    5、一个RunLoop中包含了很多运行modes,但是只能有一个currentMode,每个Mode包含了若干个Source0、Source1、Timer、Observer
    6、Mode中的Source0代表触摸事件,Source1代表基于Port的线程间通信,Timer代表定时器,Observer监听器(监听RunLoop的状态)
    7、系统默认注册了5种Mode,主线程默认在DefaultMode下运行

      1. kCFRunLoopDefaultMode:App的默认Mode,通常主线程是在这个Mode下运行
      1. UITrackingRunLoopMode:界面跟踪 Mode,用于 ScrollView 追踪触摸滑动,保证界面滑动时不受其他 Mode 影响
      1. UIInitializationRunLoopMode: 在刚启动 App 时第进入的第一个 Mode,启动完成后就不再使用,会切换到kCFRunLoopDefaultMode
      1. GSEventReceiveRunLoopMode: 接受系统事件的内部 Mode,通常用不到
      1. kCFRunLoopCommonModes: 这是一个占位用的Mode,作为标记kCFRunLoopDefaultMode和UITrackingRunLoopMode用,并不是一种真正的Mode

    8、主线程中运行的Timer,如果滑动table或者TextView,Timer会停止计数,是因为Mode自动切换到了UITrackingRunLoopMode,DefaultMode下的Timer就停止运行了。可以使用KCFRunLoopCommonModes,使加入到主线程的Timer即可以在DefaultMode下运行也可以在UITrackingRunLoopMode下运行

    9、使用GCD创建定时器

    <colgroup><col style="width: 936px;"></colgroup>
    | 
    -(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
    
    {
        //创建队列
        dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
        //1.创建一个GCD定时器
        /*
         第一个参数:表明创建的是一个定时器
         第四个参数:队列
         */
        dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
        // 需要对timer进行强引用,保证其不会被释放掉,才会按时调用block块
        // 局部变量,让指针强引用
        self.timer = timer;
        //2.设置定时器的开始时间,间隔时间,精准度
        /*
         第1个参数:要给哪个定时器设置
         第2个参数:开始时间
         第3个参数:间隔时间
         第4个参数:精准度 一般为0 在允许范围内增加误差可提高程序的性能
         GCD的单位是纳秒 所以要*NSEC_PER_SEC
         */
        dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, 2.0 * NSEC_PER_SEC, 0 * NSEC_PER_SEC);
    
        //3.设置定时器要执行的事情
        dispatch_source_set_event_handler(timer, ^{
            NSLog(@"---%@--",[NSThread currentThread]);
        });
        // 启动
        dispatch_resume(timer);
    }
    
    

    10、RunLoop主要包含下面五个类

    *   CFRunLoopRef - 获取主RunLoop和CurrentRunLoop
    *   CFRunLoopModeRef - RunLoop运行模式,可以有很多,但是只能选择一个,系统默认定义了5种
    *   CFRunLoopSourceRef - 事件源、输入源
    *   CFRunLoopTimerRef - 定时器
    *   CFRunLoopObserverRef - 观察RunLoop运行状态
    

    11、CFRunLoopObserverRef可以观测到RunLoop的整个生命周期,如下

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

    12、RunLoop的处理逻辑


    image.png

    13、CFRunLoopRef种的使用do...while处理各种时间,先处理Timers,然后Sources、Blocks、

    14、RunLoop的处理逻辑


    image.png

    15、RunLoop的应用,常驻线程的使用
    通过创建子线程,并且在子线程中的RunLoop中加入Timer或者Source,使子线程一直存在,实现常驻线程
    常驻线程可以用来记录日志,或者上传日志

    17、CFRunLoop源码
    https://opensource.apple.com/tarballs/CF/

    16、编写测试代码

    • 查看各种事件调用的source
    • 编写代码查看RunLoop的运行状态
    • 实现常驻线程

    参考文档
    1、iOS底层原理总结 - RunLoop

    相关文章

      网友评论

        本文标题:iOS RunLoop

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