工作生活

iOS RunLoop

2019-07-04  本文已影响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下运行

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、编写测试代码

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

上一篇下一篇

猜你喜欢

热点阅读