Runloop这个算是iOS开发者面试中最常见的问题之一了把,但是每次面试遇到这种问题都会菊花一紧,生怕回答的少了,同时也怕回答的不够全面。所以针对这一问题,总结了一下几个级别的开发者需要知道点进行归纳。
初级(0-3年)
如果你要去面试初级,以现在的内卷的程度,这个问题基本上是跑不了的,想当年作者还是初级的时候,连runloop都不知道是什么。。。
Runloop 是什么
Runloop是通过内部维护的事件循环来对事件/消息进行管理的一个对象
这里有两个重点
-
事件循环
-
事件/消息进行管理
什么是事件循环呢?
事件循环(状态切换)
没有消息需要处理时,休眠以避免资源占用
用户态——>内核态
有消息需要处理时,立刻被唤醒
用户态<—— 内核态
什么是事件/消息进行管理呢?
RunLoop 通过 mach_msg()函数接收、发送消息来进行管理。
它的本质是调用函数 mach_msg_trap(),相当于是一个系统调用,会触发内核状态切换。
可以做到在有事做的时候做事,没事做的时候,会由用户态切换到内核态,避免资源浪费。
如何实现事件、消息的管理
mach_msg() 函数实际上是调用了一个 Mach 陷阱 (trap),
即函数mach_msg_trap(),陷阱这个概念在 Mach 中等同于系统调用。
当你在用户态调用 mach_msg_trap() 时会触发陷阱机制,切换到内核态;
内核态中内核实现的 mach_msg() 函数会完成实际的工作,
所以说 Runloop的核心就是一个 mach_msg(),RunLoop 调用这个函数去接收消息,如果没有别人发送 port 消息过来,内核会将线程置于等待状态。例如你在模拟器里跑起一个 iOS 的 App,然后在 App 静止时点击暂停,你会看到主线程调用栈是停留在 mach_msg_trap() 这个地方。
说了这么多,应该可以对初级iOS开发者提供一个比较系统的概念,如果你还想卷的话,可以看继续往下看
中级(3-6年)
在这级别里,需要知道的就不仅仅是Runloop是什么了,更应该知道其中的数据结构和实际使用。
ps:卷的不能再卷了(╬ Ò ‸ Ó)
Runloop的数据结构
NSRunloop是CFRunloop的封装,提供了面向对象的API
typedef struct __CFRunLoopMode *CFRunLoopModeRef;
struct __CFRunLoopMode {
//...
CFStringRef _name;
//...
CFMutableSetRef _sources0; // <Set>
CFMutableSetRef _sources1;// <Set>
CFMutableArrayRef _observers; // <Array>
CFMutableArrayRef _timers; // <Array>
//...
};
///CFRunLoop.h 类型重命名
typedef struct __CFRunLoop * CFRunLoopRef;
///CFRunLoop.c 结构体
struct __CFRunLoop {
//..
CFMutableSetRef _commonModes; // <Set> String UITrackingRunLoopMode/kCFRunLoopDefaultMode
CFMutableSetRef _commonModeItems;// <Set> observer/source/timer
CFRunLoopModeRef _currentMode; //当前运行的mode
CFMutableSetRef _modes; //内置的modes;
//...
};
CFRunloop
- pthread (与线程一一对应)
- currentMode (当前的运行模式)
- modes (集合 NSMutableSet <CFRunLoopMode *>)
- commonModes(一个存储了被标记为common modes的模式集合 【NSMutableSet <NSString *>】