RunLoop 系列文章
深入浅出 RunLoop(一):初识
深入浅出 RunLoop(二):数据结构
深入浅出 RunLoop(三):事件循环机制
深入浅出 RunLoop(四):RunLoop 与线程
深入浅出 RunLoop(五):RunLoop 与 NSTimer
iOS - 聊聊 autorelease 和 @autoreleasepool:RunLoop 与 @autoreleasepool
RunLoop 与线程的关系
苹果官方文档中,RunLoop
的相关介绍写在线程编程指南中,可见RunLoop
和线程的关系不一般。Threading Programming Guide(苹果官方文档)
RunLoop
对象和线程是一一对应关系;RunLoop
保存在一个全局的Dictionary
里,线程作为key
,RunLoop
作为value
;- 如果没有
RunLoop
,线程执行完任务就会退出;如果没有RunLoop
,主线程执行完main()
函数就会退出,程序就不能处于运行状态; RunLoop
创建时机:线程刚创建时并没有RunLoop
对象,RunLoop
会在第一次获取它时创建;RunLoop
销毁时机:RunLoop
会在线程结束时销毁;- 主线程的
RunLoop
已经自动获取(创建),子线程默认没有开启RunLoop
; - 主线程的
RunLoop
对象是在UIApplicationMain
中通过[NSRunLoop currentRunLoop]
获取,一旦发现它不存在,就会创建RunLoop
对象。
未启动 RunLoop 的子线程
创建一个NSThread
的子类HTThread
并重写了dealloc
方法来观察线程的状态。执行以下代码,发现子线程执行完一次test
任务就退出销毁了,没有再执行test
任务,原因就是没有启动该线程的RunLoop
。
- (void)viewDidLoad {
[super viewDidLoad];
HTThread *thread = [[HTThread alloc] initWithTarget:self selector:@selector(test) object:nil];
[thread start];
[self performSelector:@selector(test) onThread:thread withObject:nil waitUntilDone:NO];
}
- (void)test {
NSLog(@"test on %@", [NSThread currentThread]);
}
// test on <HTThread: 0x600003cb52c0>{number = 7, name = (null)}
// HTThread dealloc
开启子线程的 RunLoop 的过程
获取 RunLoop 对象
可以通过以下方式来获取RunLoop
对象:
// Foundation
[NSRunLoop mainRunLoop]; // 获取主线程的 RunLoop 对象
[NSRunLoop currentRunLoop]; // 获取当前线程的 RunLoop 对象
// Core Foundation
CFRunLoopGetMain(); // 获取主线程的 RunLoop 对象
CFRunLoopGetCurrent(); // 获取当前线程的 RunLoop 对象
我们来看一下CFRunLoopGetCurrent()
函数是怎么获取RunLoop
对象的:
CFRunLoopRef CFRunLoopGetCurrent(void) {
CHECK_FOR_FORK();
CFRunLoopRef rl = (CFRunLoopRef)_CFGetTSD(__CFTSDKeyRunLoop);
if (rl) return rl