1、main()函数为什么能够保持不退出
因为在main函数中会调用一个 UIApplicationMain 函数,UIApplicationMain函数中会启动
主线程的RunLoop,而RunLoop是对事件循环的一种维护机制,可以做到有消息进行处理的时候,
去处理消息,没有消息处理的时候可以通过从用户态到内核态的一个切换,以避免资源占用,当前线程
也会进入休眠的状态。
2、RunLoop与Mode以及Mode和source、timer和observer之间的关系
RunLoop可以对应多个Mode,是一对多的关系,同一个Mode下可以都多个source、timer和obverse
3、RunLoop为什么可以对应多个Mode
多个Mode起到了一个相互间屏蔽的效果,只会运行当前Mode下的事件。当同一个事件需要添加到不同的Mode的时候,可以借助NSRunLoopCommonMode来实现
3、NSRunLoopCommonMode的特殊性
1)commonMode不是实际存在的一种Mode
2)是同步source/timer/Observer到多个Mode中的一种技术方案
4、观察者能够监听到的RunLoop的时间点
/* Run Loop Observer Activities */
typedef CF_OPTIONS(CFOptionFlags, CFRunLoopActivity) {
kCFRunLoopEntry = (1UL << 0), // 入口时机
kCFRunLoopBeforeTimers = (1UL << 1), // 将要处理timer相关事件
kCFRunLoopBeforeSources = (1UL << 2), // 将要处理source相关事件
kCFRunLoopBeforeWaiting = (1UL << 5), // 将要进入休眠状态,即将要从用户态切换到内核态
kCFRunLoopAfterWaiting = (1UL << 6), // 已经进入休眠状态
kCFRunLoopExit = (1UL << 7), // 退出时机
kCFRunLoopAllActivities = 0x0FFFFFFFU
};
5、CFRunLoop数据结构
struct __CFRunLoop {
CFRuntimeBase _base;
pthread_mutex_t _lock; /* locked for accessing mode list */
__CFPort _wakeUpPort; // used for CFRunLoopWakeUp
Boolean _unused;
volatile _per_run_data *_perRunData; // reset for runs of the run loop
pthread_t _pthread; // 线程
uint32_t _winthread;
CFMutableSetRef _commonModes; // NSString 类型的集合
CFMutableSetRef _commonModeItems;
CFRunLoopModeRef _currentMode; // 当前所处模式
CFMutableSetRef _modes; // CFRunLoopMode集合
struct _block_item *_blocks_head;
struct _block_item *_blocks_tail;
CFAbsoluteTime _runTime;
CFAbsoluteTime _sleepTime;
CFTypeRef _counterpart;
};
6、事件传递机制
7、滑动tableview的时候我们的定时器还会生效吗?
timer在默认情况下回运行在kCFRunLoopDefaultMode模式下,当我们滑动tableView的时候会发生Mode的切换,会切换到UITrackingRunLoopMode模式下,RunLoop的多个Mode之间是相互屏蔽的。所以,此时定时器不会生效。
可以通过void CFRunLoopAddTimer(CFRunLoopRef rl, CFRunLoopTimerRef rlt, CFStringRef modeName)
方法,将timer添加到commonMode模式下
8、RunLoop和线程的关系
线程和runLoop是一一对应的。线程默认是没有RunLoop的,需要我们手动创建
9、如何实现一个常驻线程
为当前线程开启一个RunLoop,向该RunLoop中添加一个Port/Source等维持RunLoop的事件循环,最后启动该RunLoop
+ (NSThread *)threadForDispatch{
if (thread == nil){
@synchronized (self) {
if (thread == nil){
// 线程创建
thread = [[NSThread alloc] initWithTarget:self selector:@selector(runRequest) object:nil];
[thread setName:@"com.cn"];
[thread start];
}
}
}
return thread;
}
+(void)runRequest{
// 创建一个source
CFRunLoopSourceContext context = {0,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL};
CFRunLoopSourceRef source = CFRunLoopSourceCreate(kCFAllocatorDefault, 0, &context);
// 创建一个RunLoop,同时向RunLoop的defaultMode下添加Source
CFRunLoopAddSource(CFRunLoopGetCurrent(), source, kCFRunLoopDefaultMode);
// 如果可以运行
while (runAlways) {
@autoreleasepool {
{
// 使当前RunLoop运行在defaultMode下面。
CFRunLoopRunInMode(kCFRunLoopDefaultMode, 1.0e10, true);
}
}
}
// 某一时机,当runAlways == NO时,可以保证跳出RunLoop,线程跳出
CFRunLoopRemoveSource(CFRunLoopGetCurrent(), source, kCFRunLoopDefaultMode);
// 释放source
CFRelease(source);
}