看完ibreme写的深入理解Runloop(这里),确实非常详细,描述了Runloop概念、原理及主要几个运用库。
这里我再结合几个与Runloop相关的API进行进一步的说明,更方便大家理解:
1、run相关:
在深入理解Runloop中有说到在AFNetWorking中有如下一段代码:
+ (void)networkRequestThreadEntryPoint:(id)__unused object {
@autoreleasepool {
[[NSThread currentThread] setName:@"AFNetworking"];
NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
[runLoop addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode];
[runLoop run];//为何这里要run
//如果这后面还有代码,会执行么?
NSLog(@"来这里了没")?</span>
}
}
+ (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;
}
1、那里为什么是run,不是runUntilDate等?
这里主要明白这几个api的区别,
run:是让runloop无限的运行下去,但是这里的无限运行下去有个条件,首先这个app当然是还在运行,如果app关了自然不在了,其次,必须至少有一个observer或source或timer(注意这里是或,也就有其中一个也可以)。所以这里为什么上面的例子中加入NSMachPort,虽然这个port没有处理实际的事件。
runUntilDate:这就是让这个runloop最多活不过这个date参数,如果到期了,runloop就退出。但是同样想让runloop进入运行状态,在执行这个api之前,必须往loop里添加至少一
runMode:beforeDate:从字面理解就是,在xx日期前运行xx模式,这个接口很特别,它有两个退出条件,如果在date前它处理了一个消息(如果是只有重复的timer,会一直到传入的date,但期间如果处理了其他任何其他消息,则退出),它会退出,如果在date前,即使时间还没发生(如NSTimer还没到触发点),它会退出。
所以从AFNetWorking的使用需求上,因为网络请求贯穿整个APP生命周期,所以这里用run是最合适的。
2、后面的打印代码执行了没?
因为我们已知runloop的run相关api是让runloop进入一个do{}while()循环,只要不到退出条件,它就会处于循环中,因此可以知道后面的代码是没有执行的,但是一旦loop退出循环,代码就会继续执行,当执行到最后一行后,线程结束并销毁。
2、NSTimer相关
我们一般用两种方式方式初始化NSTimer,一种是直接sheduledTimer,一种是alloc后,再把timer加到runloop里,其实两种方式是一样的。就是把Timer加入到当前runloop或指定runLoop,一旦到达指定时间,runloop就处理对应事件,但是如果当timer指定时间到达,但当前runloop还是处理着其他消息,那timer就会等runloop处理完其他消息,timer被延时操作,但是timer可以设置容忍度T,因此如果处理该timer的时间A,离预计的timer事件B,大于T,也即A>B+T,这个timer事件就会被抛弃。
这里因此有一个问题,timer是加到当前runloop或指定runloop,我们知道,除主线程外,其他线程默认是没有runloop开启的。因此如果你在辅助线程中使用timer,必须要手动让这个loop跑起来。
[runLoop run]
3、performSelector:delay:
performSelector:delay:与timer类似,就是系统会生成一个定时器,然后添加到当前runloop中,因此具体操作需要与NSTimer一致。
4、dispatch_after
dispatch本身就是消息队列(我们可以认为是就是一个已经开启的runloop),与runloop不一样,因此不会像timer一样,需要考虑当前线程是否有runloop,以及runloop是否运行。
5、总结
NSThread * thread = [[NSThread alloc] initWithTarget:self selector:@selector(doThread:) object:nil];
[thread start];
-(void)doThread:(id)ni
{
//这个方法在
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[self doSm1];
});
[self performSelector:@selector(doSm2) withObject:nil afterDelay:2];
[NSTimer scheduledTimerWithTimeInterval:3 target:self selector:@selector(doSm3) userInfo:nil repeats:NO];
}
上面代码中,哪些方法会执行呢?
结果:1执行,2、3不执行。