1.RunLoop概念
是一个让线程能随时处理事件但是不退出的机制,它是一个对象,这个对象管理了其需要处理的事件和消息,并且提供了一个入口函数,线程执行了这个函数以后,就会处于这个函数内部 接收消息,等待,处理的循环中,这个这个循环结束,函数返回。
2.RunLoop与线程的关系
苹果不允许直接创建 RunLoop,它只提供了两个自动获取的函数:CFRunLoopGetMain() 和 CFRunLoopGetCurrent()。
可以看出,线程和RunLoop是一一对应的,其关系是保存在一个全局的Dictionary中,线程创建的时候没有RunLoop,你如果不获取,它就一直没有,RunLoop的创建是在第一次获取的时候,RunLoop的销毁是在线程结束的时候,所以你只能在一个线程内部获取其RunLoop(主线程除外)
3.RunLoop 的 Mode
苹果公开提供的 Mode 有两个:
1 NSDefaultRunLoopMode(kCFRunLoopDefaultMode)默认,空闲状态
2 UITrackingRunLoopMode ScrollView滑动时
同时苹果还提供了一个操作 Common 标记的字符串:kCFRunLoopCommonModes (NSRunLoopCommonModes),你可以用这个字符串来操作 Common Items,或标记一个 Mode 为 “Common”。使用时注意区分这个字符串和其他 mode name
RunLoop其内部是一个 do-while 循环。当你调用 CFRunLoopRun() 时,线程就会一直停留在这个循环里;直到超时或被手动停止,该函数才会返回。
4.AFNetworking
+ (void)networkRequestThreadEntryPoint:(id)__unused object {
@autoreleasepool {
[[NSThread currentThread] setName:@"AFNetworking"];
NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
[runLoop addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode];
[runLoop run];
}
}
+ (NSThread *)networkRequestThread {
static NSThread *_networkRequestThread = nil;
static dispatch_once_t oncePredicate;
dispatch_once(&oncePredicate, ^{
_networkRequestThread = [[NSThread alloc] initWithTarget:self selector:@selector(networkRequestThreadEntryPoint:) object:nil];
[_networkRequestThread start];
});
return _networkRequestThread;
}
RunLoop 启动前内部必须要有至少一个 Timer/Observer/Source,所以 AFNetworking 在 [runLoop run] 之前先创建了一个新的 NSMachPort 添加进去了。通常情况下,调用者需要持有这个 NSMachPort (mach_port) 并在外部线程通过这个 port 发送消息到 loop 内;但此处添加 port 只是为了让 RunLoop 不至于退出,并没有用于实际的发送消息。
- (void)start {
[self.lock lock];
if ([self isCancelled]) {
[self performSelector:@selector(cancelConnection) onThread:[[self class] networkRequestThread] withObject:nil waitUntilDone:NO modes:[self.runLoopModes allObjects]];
} else if ([self isReady]) {
self.state = AFOperationExecutingState;
[self performSelector:@selector(operationDidStart) onThread:[[self class] networkRequestThread] withObject:nil waitUntilDone:NO modes:[self.runLoopModes allObjects]];
}
[self.lock unlock];
}
当需要这个后台线程执行任务时,AFNetworking 通过调用 [NSObject performSelector:onThread:..] 将这个任务扔到了后台线程的 RunLoop 中。
保持RunLoop不退出的方法启动前内部必须要有至少一个 Timer/Observer/Source,AFNetworking中是持有一个NSMachPort,而SRWebSocket中是用dispatch_group_wait和dispatch_group_leave,单独创建一个NSRunLoop的分类
网友评论