Runloop基本原理
2022-04-12 本文已影响0人
胡智钦
① Runloop可以做什么?
- 保住线程,处理crash
场景:在捕获异常的时候,强制程序Runloop,就不会发生闪退的情况
拓展:📚iOS runloop解决App crash并获取日志
// 核心代码部分
/*在主线程中调用堆栈中异常信号,当捕获到异常信号的时候,用Runloop保住线程,以致于程序不会立马crash*/
CFRunLoopRef runLoop = CFRunLoopGetCurrent();
CFArrayRef allModes = CFRunLoopCopyAllModes(runLoop);
while (true) {
for (NSString *mode in (__bridge NSArray *)allModes) {
// 快速切换Mode -> CFRunLoopRunInMode
CFRunLoopRunInMode((CFStringRef)mode, 0.001, false);
}
}
- 线程保活 (4种保活方式:NSThread / NSOperation / GCD / NSCondition(条件锁))
场景:创建很多子线程执行完任务后,会自动销毁,但频繁创建后又销毁会造成资源浪费,所以可以用Runloop进行线程保活
拓展:📚NSThread、GCD、NSOperation多线程区别
- 监测卡顿
场景:造成卡顿主要原因耗时操作造成主线程阻塞,比如大量的:数据解析、动画加载、图片绘制、文件下载等
拓展:📚YYFPSLabel讲解
② Runloop跟线程有什么关系?
- 一一对应,键值对形式存储
Key(线程) : Value(Runloop)
具体方法见Foundation -> CFRunloop.c -> CFRunloopGet0 1422行代码
③ Runloop的组成?
- Mode -> sources(事件源) / timer(定时器) / observer(监测)
如果子线程sources或者timer为null(
而主线程可为null
),Runloop会直接休眠
具体方法见Foundation -> CFRunloop.c -> __CFRunloopModeIsEmpty 870行代码
CFRunloopRef 和 NSRunloop 区别
CFRunloopRef是纯C语言实现的,线程安全
。
NSRunloop是封装的面向对象语言,线程不安全
。
sources中有
sources0
和sources1
sources0
:非port事件,用来处理手动触发的事件。例如:滑动、点击等
sources1
:系统port的内核事件源,可以通过内核和其它线程之间发消息,还可以主动唤醒Runloop
observer:适用场景卡顿监测(硬件有关:CPU程序指令、GPU图像渲染)
1.影响CPU性能的因素:IO任务、过多的线程抢占CPU资源、温度过高降频
2.影响GPU性能的因素:显存频率、渲染算法、大计算量
/*子线程监测主线程:使用 CFRunLoopAddObserver 检测主线程是否卡顿*/
//将观察者添加到主线程runloop的common模式下的观察中
CFRunLoopAddObserver(CFRunLoopGetMain(), runLoopObserver, kCFRunLoopCommonModes);
④ Runloop的如何启动和停止?
【启动方式】
- 无条件启动(最简单,最不可取,会引起死循环)
[[NSRunloop currentRunLoop] run];
/*本质是while调用[[NSRunloop currentRunLoop] runModel:NSDefaultLoopMode beforeDate:[NSDate distantFuture]];*/
- 设置超时时间
[[NSRunloop currentRunLoop] runUntilDate:[NSDate distantFuture]];
/*本质是while调用[[NSRunloop currentRunLoop] runModel:NSDefaultLoopMode beforeDate:[NSDate distantFuture]];*/
- 特殊模式
[[NSRunloop currentRunLoop] runModel:NSDefaultLoopMode beforeDate:[NSDate distantFuture]];
【停止方式】
- 线程停止强引用
CFRunLoopStop(CFRunLoopGetCurrent());
// NSThread
self.thread = nil;