iOS RunLoop

306 阅读2分钟

RunLoop概念 RunLoop是通过内部维护的事件循环(Event Loop)来对事件/消息进行管理的一个对象 没有消息处理时,休眠以避免资源占用;有消息需要处理时,立刻被唤醒 为什么main函数不会退出 int main(int argc, char * argv[]) { @autoreleasepool { return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); } } 复制代码 UIApplicationMain内部默认开启了主线程的RunLoop,并执行了一段无限循环的代码(不是简单的for循环或while循环)UIApplicationMain函数一直没有返回,不断地接收处理消息以及等待休眠,所以运行程序之后,会保持持续运行状态 RunLoop结构体 Source1 : 基于Port的线程间通信 Source0 : 触摸事件、PerformSelector Timer : 定时器 Observer : 监听器,用于监听RunLoop的状态 RunLoop和线程 线程和RunLoop是一一对应的,其映射关系是保存在一个全局的Dictionary里,线程作为key,RunLoop作为value 自己创建的线程默认是没有开启RunLoop的 runloop在第一次获取时被创建,在线程结束时被销毁 对于主线程来说,runloop在程序一启动就默认创建好了 对于子线程来说,runloop是懒加载的,只有当我们使用的时候才会创建,所以在子线程用定时器要注意:确保子线程的runloop被创建,不然定时器不会回调 怎么创建一个常驻线程 为当前线程开启一个RunLoop(第一次调用[NSRunLoop currentRunLoop]方法时,实际是会先去创建一个RunLoop) 向当前RunLoop中添加一个Port/Source等维持RunLoop的事件循环(如果RunLoop的mode中一个item都没有,RunLoop会退出) 启动该RunLoop @autoreleasepool { NSRunLoop *runLoop = [NSRunLoop currentRunLoop]; [runLoop addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode]; [runLoop run]; } 复制代码

输出下边代码的执行顺序 NSLog(@"1"); dispatch_async(dispatch_get_global_queue(0, 0), ^{ NSLog(@"2"); [self performSelector:@selector(test) withObject:nil afterDelay:10]; NSLog(@"3"); }); NSLog(@"4"); - (void)test{ NSLog(@"5"); } 复制代码 答案是1423,test方法并不会执行 原因是:如果是带afterDelay的延时函数,会在内部创建一个NSTimer,然后添加到当前线程的RunLoop中,也就是如果当前线程没有开启RunLoop,该方法会失效 那么我们改成: dispatch_async(dispatch_get_global_queue(0, 0), ^{ NSLog(@"2"); [[NSRunLoop currentRunLoop] run]; [self performSelector:@selector(test) withObject:nil afterDelay:10]; NSLog(@"3"); }); 复制代码 test方法依然不执行 原因是:如果RunLoop的mode中一个item都没有,RunLoop会退出 即在调用RunLoop的run方法后,由于其mode中没有添加任何item去维持RunLoop的事件循环,RunLoop随即还是会退出,所以我们自己启动RunLoop,一定要在添加item后 dispatch_async(dispatch_get_global_queue(0, 0), ^{ NSLog(@"2"); [self performSelector:@selector(test) withObject:nil afterDelay:10]; [[NSRunLoop currentRunLoop] run]; NSLog(@"3"); });

jq.qq.com/?_wv=1027&k… (QQ交流裙 密码:123)