AFN常驻线程的理解(从2.x到3.x)
最常见的问题:AFN为什么添加一条常驻线程 问这个问题的人大部分是停留在2.x版本的理解,从3.x开始AFN已经不需要常驻线程了。这里涉及到从NSUrlNSURLConnection到NSURLSession的演变。
2.x版本常驻线程的分析
在2.x版本的AFN中,使用的是NSURLCollection进行封装。NSURLConnection的网络请求是异步发起的,事件和结果的回调在原来线程的RunLoop中进行。
-
在请求完成后我们需要对数据进行一些序列化处理,或者错误处理。如果我们在主线中处理这些事情很明显是不合理的。不仅会导致UI的卡顿,甚至受到默认的RunLoopModel的影响,我们在滑动tableview的时候,会导致时间的处理停止。
-
这里时候我们就需要一个子线程来处理事件和网络请求的回调了。但是,子线程在处理完事件后就会自动结束生命周期,这个时候后面的一些网络请求得回调我们就无法接收了。所以我们就需要开启子线程的RunLoop来保存线程的常驻。
-
当然我们可以每次发起一个请求就开启一条子线程,但是这个想一下就知道开销有多大了。所以这个时候保活一条线程来对请求得回调处理是比较好的一个方案。
-- 下面是2.x版本的常驻线程的开启代码 --
+ (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的开启。至于这些详细信息,就不在这里另行记录,可以再去查询详细的信息。
3.x版本不在常驻线程的分析
在3.x的AFN版本中使用的是NSURLSession进行封装。对比于NSURLConnection,NSURLSession不需要在当前的线程等待网络回调,而是可以让开发者自己设定需要回调的队列。
所以在3.x版本中AFN使用了NSOperationQueue对网络回调的管理,并且设置maxConcurrentOperationCount为1,保证了最大的并发数为1,也就是说让网络请求串行执行。避免了多线程环境下的资源抢夺问题。
总结
关于AFN为什么要开辟一条常驻线程的问题,我们得区分清楚,常驻线程其实是在2.x版本中的,究其原因是2.x和3.x版本分别使用的是NSURLConnection和NSURLSession。由于NSURLSession不需要再当前线程等待网络请求得回调结果,所以说在AFN中就不需要常驻线程等待回调,而是交给NSOperationQueue来处理,让系统自己来决定是否需要开启新的线程。
并且设置maxConcurrentOperationCount为1,让回调串行执行。