RunLoop理解

2018-04-02  本文已影响13人  小强简书

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的分类

上一篇 下一篇

猜你喜欢

热点阅读