Runloop
2023-01-29 本文已影响0人
e521
1、什么是Runloop?
- 运行循环,俗称为跑圈,内部就是一个do-while循环,用于处理应用的各种事件,保证程序的正常运行。
2、Runloop能做些什么?
- 处理crash问题
- 线程保活
- 检测、优化卡顿问题
3、线程和Runloop有什么关系?
- 线程和Runloop是一一对应的,且以key和value的形式进行存储的。
if (!__CFRunLoops) {
__CFUnlock(&loopsLock);
// 创建字典
CFMutableDictionaryRef dict = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, NULL, &kCFTypeDictionaryValueCallBacks);
// 创建主线程
CFRunLoopRef mainLoop = __CFRunLoopCreate(pthread_main_thread_np());
// 建立主线程和runloop之间的联系
CFDictionarySetValue(dict, pthreadPointer(pthread_main_thread_np()), mainLoop);
if (!OSAtomicCompareAndSwapPtrBarrier(NULL, dict, (void * volatile *)&__CFRunLoops)) {
CFRelease(dict);
}
4.Runloop的构成
- Runloop是由多个mode组成 mode又由sources0,sources1,observers ,timers构成
- sources0是非基于port的任务事件,需要手动唤醒线程
- sources1 用于处理内核事件,即port相关的,能主动唤醒runloop
5.如何启动runloop
启动runlopp的三种方式:
- (void)run NS_SWIFT_UNAVAILABLE_FROM_ASYNC("run cannot be used from async contexts.");
- (void)runUntilDate:(NSDate *)limitDate NS_SWIFT_UNAVAILABLE_FROM_ASYNC("run(until:) cannot be used from async contexts.");
- (BOOL)runMode:(NSRunLoopMode)mode beforeDate:(NSDate *)limitDate
前两种方式是基于while循环的调用第三种启动方式,前两种方式是一种无限循环。
public func run() {
while run(mode: .default, before: Date.distantFuture) { }
}
public func run(until limitDate: Date) {
while run(mode: .default, before: limitDate) && limitDate.timeIntervalSinceReferenceDate > CFAbsoluteTimeGetCurrent() { }
}
public func run(mode: RunLoop.Mode, before limitDate: Date) -> Bool {
if _cfRunLoop !== CFRunLoopGetCurrent() {
return false
}
let modeArg = mode._cfStringUniquingKnown
if _CFRunLoopFinished(_cfRunLoop, modeArg) {
return false
}
let limitTime = limitDate.timeIntervalSinceReferenceDate
let ti = limitTime - CFAbsoluteTimeGetCurrent()
CFRunLoopRunInMode(modeArg, ti, true)
return true
}
6、Runloop有几种状态
- kCFRunLoopEntry:进入loop,在调用__CFRunLoopRun函数前,会被标记为这个状态。
- kCFRunLoopBeforeTimers:触发 Timer 回调,判断是有Timer触发的话会走Timer回调,走回调前会被标记为这个状态。
- kCFRunLoopBeforeSources:触发 Source0 回调,判断是Source0触发的话会走Source0回调,走回调前会被标记为这个状态。
- kCFRunLoopBeforeWaiting:将要进入休眠。等待 mach_port 消息,在处理完事件后,会标记为这个状态,然后进入到内部的do while循环中等待激活。
- kCFRunLoopAfterWaiting:从休眠中唤醒。 接收 mach_port 消息,已经被激活,在处理事件前会标记为这个状态。然后开始处理事件。
- kCFRunLoopExit:退出 loop
7、主线程需要保活吗?保活的方式有几种?
- 主线程不需要保活,子线程的保活方式有两种方式,一种是通过runloop,一种是通过NSCondition方式进行保活,runloop的方式可以细分为通过timer和port的方式保活
参考链接:
iOS 线程保活
Runloop
RunLoop从源码到应用全面解析