本文属于梳理性文章,许多地方尚需深入,感谢Mrpeak大神,文末已附原文地址;燃烧的小宇宙,加油2019!
RunLoop-OC:【RunLoop-OC】
RunLoop-Swift:【RunLoop-Swift】
辅助理解知识点:
mach_msg:
这是系统内核在某个port收发消息所使用的函数;
注意,收消息和发消息调用的都是这个函数,只是参数不同;
发送使用MACH_SEND_MSG;接收使用MACH_RCV_MSG;
可以简单将mach_msg理解为多进程间的一种通信机制;不同的进程可以使用同一个消息队列来交流数据;
当使用mach_msg从消息队列里读取msg时,可以在参数中设置超时时间timeout;
如果在timeout之前没有读到msg,当前线程会处于休眠状态;
Runloop实现了类似的基于线程的机制:
当线程无法从Runloop中读取信息时,如没有任务可执行,能够进入sleep状态;各个线程可以通过运行循环通信;
Runloop:
Runloop是啥:
Runloop是Apple设计的,一种在当前线程,持续调度各种任务的运行机制;
这张图很大,我在文末将图分拆成了诸多小图,方便查看;
NSTimer问题:
关于NSTimer的调度问题:NSTimer默认只会调度kCFRunLoopDefaultModel这个模式;
当scrollView滑动的时候,runloop会进入UITrackingRunLoopMode,那么在doTimer的时候就不会触发NSTimer的任务了;
解决办法是将NSTimer也加入到UITrackingRunLoopMode,而由于UITrackingRunLoopMode也是一种common mode,所以直接把NSTimer加入到kCFRunLoopCommonModes里那么所有被标记为common mode就都支持NSTimer了;timer不用的使用记得调用invalidate方法,否则无法得到释放;
由于private mode的存在(开发者也可以创建private mode),即便这样也不能满足所有场景,好在主线程Runloop大部分都是以kCFRunLoopDefaultModel和UITrackingRunLoopMode两种mode运行的,而且如果你的任务对时间非常敏感,最好也不要用NSTimer;
RunLoop的使用:
使用RunLoop的场景分两类:一类是开发者通过runloop执行自己的任务,比如mainQueue,timer等;
另一类就是通过runloop观测分析主线程的运行状态(当前runloop处于哪个activity,或处于那个mode);
还可以建立自己的runloop mode,设置common或者private,并将自己想要调度的任务通过如下API放入该mode:
CF_EXPORT CFRunLoopRunResult CFRunLoopRunInMode(CFRunLoopMode mode, CFTimeInterval seconds, Boolean returnAfterSourceHandled);
小图拆分:
参考文章:
【解密Runloop】-【http://mrpeak.cn/blog/ios-runloop/】