RunLoop 相关逻辑流程
上图是笔者从网上找到的一张 RunLoop 运行的相关流程逻辑图。具体来说主要执行逻辑是这样的:
- 1、通知观察者 RunLoop 已经启动。
- 2、通知观察者即将要开始定时器。
- 3、通知观察者任何即将启动的非基于端口的源。
- 4、启动任何准备好的非基于端口的源(Source0)。
- 5、如果基于端口的源(Source1)准备好并处于等待状态,进入步骤9。
- 6、通知观察者线程进入休眠状态。
- 7、将线程置于休眠状态,知道下面的任一事件发生才唤醒线程。
. 某一事件到达基于端口的源
. 定时器启动。
. RunLoop 设置的时间已经超时。
. RunLoop 被唤醒。 - 8、通知观察者线程将被唤醒。
- 9、处理未处理的事件。
.如果用户定义的定时器启动,处理定时器事件并重启RunLoop。进入步骤2。
.如果输入源启动,传递相应的消息。
.如果RunLoop被显示唤醒而且时间还没超时,重启RunLoop。进入步骤2 - 10、通知观察者RunLoop结束。
RunLoop 实际应用
Run Loop应用实践
Run Loop主要有以下三个应用场景:
- 维护线程的生命周期,让线程不自动退出,isFinished为Yes时退出。
NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
[runLoop addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode];
while (!self.isCancelled && !self.isFinished) {
@autoreleasepool {
[runLoop runUntilDate:[NSDate dateWithTimeIntervalSinceNow:3]];
}
}
- 创建常驻线程,执行一些会一直存在的任务。该线程的生命周期跟App相同
@autoreleasepool {
NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
[runLoop addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode];
[runLoop run];
}
- 在一定时间内监听某种事件,或执行某种任务的线程
如下代码,在30分钟内,每隔30s执行onTimerFired:。这种场景一般会出现在,如我需要在应用启动之后,在一定时间内持续更新某项数据。
@autoreleasepool {
NSRunLoop * runLoop = [NSRunLoop currentRunLoop];
NSTimer * udpateTimer = [NSTimer timerWithTimeInterval:30
target:self
selector:@selector(onTimerFired:)
userInfo:nil
repeats:YES];
[runLoop addTimer:udpateTimer forMode:NSRunLoopCommonModes];
[runLoop runUntilDate:[NSDate dateWithTimeIntervalSinceNow:60*30]];
}
- AFNetworking中RunLoop的创建
+ (void)networkRequestThreadEntryPoint:(id)__unused object {
@autoreleasepool {
[[NSThread currentThread] setName:@"AFNetworking"];
NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
// 这里主要是监听某个 port,目的是让这个 Thread 不会回收
[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;
}