1. Runloop结构

2020-10-13  本文已影响0人  算命的李老师

什么是一个Runloop

是通过内部维护的事件循环(==用户态 和 内核态 相互转换==)来对事件或消息进行管理的一个对象

事件循环是什么?

一个UI事件,一个timer,一个系统delegate。(viewDidLoad也是系统的delegate,而且要一套执行完,例如tableview的所有代理)都称之为runloop(不是NSRunloop),runloop实际上是从接收消息,然后处理完消息的一个完整过程。

NSRunloop 是什么

是CFRunloop的封装,提供了面向对象的api

CFRunloop数据结构
// runloop数据结构
struct __CFRunLoop {
    CFMutableSetRef _commonModes;    // Set<CFStringRef>
    CFMutableSetRef _commonModeItems; // Set<Source/Observer/Timer>
    CFRunLoopModeRef _currentMode;    // Current Runloop Mode
    CFMutableSetRef _modes;           // Set<CFRunLoopModeRef>
    ...
};

// mode数据结构
struct __CFRunLoopMode {
    CFStringRef _name;            // Mode名字, 
    CFMutableSetRef _sources0;    // Set<CFRunLoopSourceRef>
    CFMutableSetRef _sources1;    // Set<CFRunLoopSourceRef>
    CFMutableArrayRef _observers; // Array<CFRunLoopObserverRef>
    CFMutableArrayRef _timers;    // Array<CFRunLoopTimerRef>
    ...
};

//CFRunLoopModeRef 类型

1. kCFRunLoopDefaultMode: //默认mode,通常主线程在这个 Mode 下运行。

2. UITrackingRunLoopMode://追踪mode,保证Scrollview滑动顺畅不受其他 mode 影响。
 
3. UIInitializationRunLoopMode://启动程序后的过渡mode,启动完成后就不再使用。
 
4: GSEventReceiveRunLoopMode://Graphic相关事件的mode,通常用不到。
 
5: kCFRunLoopCommonModes://占位mode,作为标记DefaultMode和CommonMode用。

//Runloop 状态

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

总结:

Runloop有多个Mode(原因:为了屏蔽消息,每个Mode做当前任务下的事情),每个Mode拥有多个sources(集合),obvservers(数组),timer(数组)

mode切换和item依赖

a 主线程的runloop自动创建,子线程的runloop默认不创建(在子线程中调用NSRunLoop *runloop = [NSRunLoop currentRunLoop];
获取RunLoop对象的时候,就会创建RunLoop);

b runloop退出的条件:app退出;线程关闭;设置最大时间到期;modeItem为空;

c 同一时间一个runloop只能在一个mode,切换mode只能退出runloop,再重进指定mode(隔离modeItems使之互不干扰);

d 一个item可以加到不同mode;一个mode被标记到commonModes里(这样runloop不用切换mode)。

Runloop本质:

mach port和mach_msg()。

Mach是XNU的内核,进程、线程和虚拟内存等对象通过==端口==发消息进行通信

无线程消息时

Runloop通过mach_msg()函数发送消息,如果没有port 消息,内核会将线程置于等待状态 mach_msg_trap() 。

有线程消息时

判断消息类型处理事件,并通过modeItem的callback回调

Runloop有两个关键判断点,一个是通过msg决定Runloop是否等待,一个是通过判断退出条件来决定Runloop是否循环。

Runloop处理事件模型

RunLoop 的运行逻辑

source0 无法唤醒runloop,事件是在source1捕获,在source0执行

上一篇 下一篇

猜你喜欢

热点阅读