NSURLSessionDownloadTask
前面三篇,分析了关于AFNetworking的GET和POST请求方法,以及AFNetworking将系统的协议封装成为了一个AFNetworking自己的DataTaskDelegate的方法。通过本篇AFNetworking,我们将分析AFNetworking下载任务操作。
NSURLSessionDownloadTask
- (NSURLSessionDownloadTask *)downloadTaskWithRequest:(NSURLRequest *)request
progress:(void (^)(NSProgress *downloadProgress)) downloadProgressBlock
destination:(NSURL * (^)(NSURL *targetPath, NSURLResponse *response))destination
completionHandler:(void (^)(NSURLResponse *response, NSURL *filePath, NSError *error))completionHandler
{
__block NSURLSessionDownloadTask *downloadTask = nil;
url_session_manager_create_task_safely(^{
downloadTask = [self.session downloadTaskWithRequest:request];
});
[self addDelegateForDownloadTask:downloadTask progress:downloadProgressBlock destination:destination completionHandler:completionHandler];
return downloadTask;
}
通过系统提供的NSURLSession实力化对象创建一个下载任务,传入的是一个下载路径的请求request。
这里面,我们稍微关心一下url_session_manager_create_task_safely是做了什么操作???
static void url_session_manager_create_task_safely(dispatch_block_t _Nonnull block) {
if (block != NULL) {
if (NSFoundationVersionNumber < NSFoundationVersionNumber_With_Fixed_5871104061079552_bug) {
// Fix of bug
// Open Radar:http://openradar.appspot.com/radar?id=5871104061079552 (status: Fixed in iOS8)
// Issue about:https://github.com/AFNetworking/AFNetworking/issues/2093
dispatch_sync(url_session_manager_creation_queue(), block);
} else {
block();
}
}
}
在创建下载任务的时候,block块不为空,因此,通过创建了同步线程阻塞线程来创建一个下载任务作业,我们不难看出,在GET和POST到现在的下载任务,凡事关于到下载数据请求的AFNetworking多做了线程安全处理,这是一个很好的操作。
思考:为什么不直接在下载任务中使用dispatch_sync()而要疯转一个AFURLSessionManager???
个人认为,其实直接使用是没用问题的,只是无疑的,但是面对AFNetworking,多个需要考虑线程安全问题的框架,使用一个SessionManager来管理线程安全显得尤为重要,这样可以提高代码的重用性。
最后,在返回下载任务之前,添加下载协议。
- (void)addDelegateForDownloadTask:(NSURLSessionDownloadTask *)downloadTask
progress:(void (^)(NSProgress *downloadProgress)) downloadProgressBlock
destination:(NSURL * (^)(NSURL *targetPath, NSURLResponse *response))destination
completionHandler:(void (^)(NSURLResponse *response, NSURL *filePath, NSError *error))completionHandler
{
AFURLSessionManagerTaskDelegate *delegate = [[AFURLSessionManagerTaskDelegate alloc] initWithTask:downloadTask];
delegate.manager = self;
delegate.completionHandler = completionHandler;
if (destination) {
delegate.downloadTaskDidFinishDownloading = ^NSURL * (NSURLSession * __unused session, NSURLSessionDownloadTask *task, NSURL *location) {
return destination(location, task.response);
};
}
downloadTask.taskDescription = self.taskDescriptionForSessionTasks;
[self setDelegate:delegate forTask:downloadTask];
delegate.downloadProgressBlock = downloadProgressBlock;
}
在协议中,我们进行了数据的保存,包括管理者身份,完成的回调,任务的描述等。
这样就基本实现了下载功能。
上传操作和下载操作大同小异,就不再这里赘述了。
回顾AFNetworking
如果是从第一篇坚持看到这里,那么AFNetworking的基本网络请求过程就会有大概的印象。在AFNetworking中,小编觉得有以下部分是值得我们去学习和借鉴的:
- 首当其冲的就是线程安全。
我们知道,Objective-C不像Swift let一样具有线程安全,因此,在网络请求时候,如果不加同步锁会产生严重的问题。AFNetworking通过GCD来实现线程安全问题。 - 对协议的封装,通常,我们使用到协议的地方有UITextView,UITableView,UICollectionView,网络请求,蓝牙请求等都会用到协议,如果,我们需要封装这些功能,面对协议我们就可以效仿AFNetworking,将协议利用一个自定义类进行封装,通过协议来赋值给自定义中的属性。然后,在外部就可以直接调用成员属性来实现代理的效果。这样的好处无疑是使得代码更加高效紧凑。
- 大量的错误判断处理,AFNetworking作为网络请求的框架,在网络请求的同时会面对多种错误问题,AFNetworking通过大量的判断来进行错误处理,这个在对于开发中的错误处理给予了方向。
- Block块使用,从开始写RAC,到Masonry,再到AFNetworking,我们无处不用到Block,对于Block,我相信大家已经不具有恐惧心里,相反会喜欢上Block的使用,AFNetworking在使用Block调用时候,会先判断是否Block有值,如果有则调用,否则,不调用,这个设计思路也是我们可以借鉴的。
预告篇
下一篇,我们将介绍AFNetworking判断设备的联网状态源码分析,并且,会分析AFNetworking缓存图片进行介绍。尽可能理解缓存机制的做法。
中文源码下载
AFNetworking中文源码:GitHub.