NSURLSession与NSURLConnection区别
2013 年的 WWDC 大会上,iOS 7.0 推出了 NSURLSession,对 Foundation URL 加载系统进行了彻底的重构,提供了更丰富的 API 来处理网络请求,如:支持 http2.0 协议、直接把数据下载到磁盘、同一 session 发送多个请求、下载是多线程异步处理和提供全局的 session 并可以统一配置等等,提高了 NSURLSession 的易用性、灵活性,更加地适合移动开发的需求。
在iOS9以后,NSURLConnection过期废弃.
NSURLSession 有三种网络操作方案:
- 普通网络请求
NSURLSessionDataTask
- 上传
NSURLSessionUploadTask
- 下载
NSURLSessionDownloadTask
创建的 task 都是挂起状态,需要 resume 才能启动.
普通网络请求 和 上传网络请求
- 普通: 当服务器返回的数据较小时,NSURLSession 与 NSURLConnection 执行普通任务的操作步骤没有区别。
- 上传: 执行上传任务时,NSURLSession 与 NSURLConnection 一样需要设置 POST 请求的请求体进行上传。
下载任务方式
- NSURLConnection下载文件时,先是将整个文件下载到内存,然后再写入到沙盒,如果文件比较大,就会出现内存暴涨的情况。
- 而使用 NSURLSessionDownloadTask 下载文件,会默认下载到沙盒中的 tmp 文件中,不会出现内存暴涨的情况,但是在下载完成后会把 tmp 中的临时文件删除,需要在初始化任务方法时,在 completionHandler 回调中增加保存文件的代码。
请求方法的控制
- NSURLConnection 实例化对象,实例化开始,默认请求就发送(同步发送),不需要调用 start 方法。而 cancel 可以停止请求的发送,停止后不能继续访问,需要创建新的请求。
- NSURLSession 有三个控制方法,取消(cancel)、暂停(suspend)、继续(resume),暂停以后可以通过继续恢复当前的请求任务。
断点续传的方式
NSURLConnection 进行断点下载,通过设置访问请求的 HTTPHeaderField 的 Range 属性,开启运行循环,NSURLConnection 的代理方法作为运行循环的事件源,接收到下载数据时代理方法就会持续调用,并使用 NSOutputStream 管道流进行数据保存。
NSURLSession 进行断点下载,当暂停下载任务后,如果 downloadTask(下载任务)为非空,调用 cancelByProducingResumeData:(void (^)(NSData *resumeData))completionHandler 这个方法,这个方法接收一个参数,完成处理代码块,这个代码块有一个 NSData 参数 resumeData,如果 resumeData 非空,我们就保存这个对象到视图控制器的 resumeData 属性中,在点击再次下载时,通过调用[ [self.session downloadTaskWithResumeData:self.resumeData] resume]方法进行继续下载操作。
经过以上比较可以发现,使用 NSURLSession 进行断点下载更加便捷。
配置信息
NSURLSessionConfiguration
类的参数可以设置配置信息,其决定了cookie
,安全
和高速缓存策略
,最大主机连接数
,资源管理
,网络超时
等配置。NSURLConnection 不能进行这个配置,相比较与 NSURLConnection 依赖与一个全局的配置
对象,缺乏灵活性而言,NSURLSession 有很大的改进了。
有三个方法来创建NSURLSessionConfiguration:
defaultSessionConfiguration 使用全局的cache,cookie,使用硬盘来缓存数据。
ephemeralSessionConfiguration 临时session配置,与默认配置相比,这个配置不会将缓存、cookie等存在本地,只会存在内存里,所以当程序退出时,所有的数据都会消失
backgroundSessionConfiguration 后台session配置,与默认配置类似,不同的是会在后台开启另一个线程来处理网络数据。
一旦创建了NSURLSessionConfiguration就可以给它设置各种属性
看NSURLSessionConfiguration的头文件:
1 | @interface NSURLSessionConfiguration : NSObject <NSCopying> |
URLSessionTask
NSURLSessionTask是一个抽象类,其下有4个实体子类可以直接使用:NSURLSessionDataTask、NSURLSessionUploadTask、NSURLSessionDownloadTask、NSURLSessionStreamTask。这四个子类封装了现代程序四个最基本的网络任务:获取数据,比如JSON或者XML,上传文件和下载文件还有数据流的获取。
NSURLSession比NSURLConnection最方便的地方就是任务可以暂停,继续。在网络请求中,真正去执行下载或者上传任务的就是URLSessionTask,我们来看一下它常用的方法:- (void)resume;
当使用NSURLSession创建一个NSURLSessionTask任务时,要手动调用此方法,任务才会开启,而NSURLConnection默认开启。- (void)suspend;
暂停任务方法,手动调用会暂停当前任务,再次开启此任务时,会从紧接上次任务开始,会面会说到如何暂停任务再开启任务。- (void)cancel;
取消任务。
NSURLSessionTask还有个属性,@property (readonly) NSURLSessionTaskState state; 此属性标识当前任务的状态,枚举类型
1 | typedef NS_ENUM(NSInteger, NSURLSessionTaskState) { |
上面说到的四个类,都直接或间接继承NSURLSessionTask,所有NSURLSessionTask的方法或者属性这四个类都有,那么,简单说一下这四个类都是干什么的。
NSURLSessionDataTask
NSURLSessionDataTask是开发中使用频率最高的,我们平常使用的GET和POST请求都是通过它来实现的,如果请求的数据简单并且不需要对获取的数据进行复杂操作,我们使用 Block 解析返回的数据即可。
另外我们也可以设置session的代理来实时的监听数据,我们可以使用NSURLSession的+ (NSURLSession *)sessionWithConfiguration:(NSURLSessionConfiguration *)configuration;
和+ (NSURLSession *)sessionWithConfiguration:(NSURLSessionConfiguration *)configuration delegate:(nullable id <NSURLSessionDelegate>)delegate delegateQueue:(nullable NSOperationQueue *)queue;
这两个方法来设置代理,具体的协议为NSURLSessionDelegate
,它有四个直接或间接子协议NSURLSessionTaskDelegate
,NSURLSessionDownloadDelegate
和 NSURLSessionStreamDelegate
、NSURLSessionDataDelegate
NSURLSessionDownloadTask
NSURLSessionDownloadTask在下载文件的时候,是将数据一点点地写入本地的临时文件。所以在 completionHandler 这个 block 里,我们需要把文件从一个临时地址移动到一个永久的地址保存起来:
断点续传
说一下开发中经常用到的断点续传。在开发中,我们经常由于某种原因,在下载或上传的时候往往不能一次性下载或上传完,有可能下载或上传了一半就终止了,这时候当条件满足继续下载或上传时,我们不希望从头开始,这时候就可以使用断点续传。它的大概思路是:
- 某种限制,续传暂停
- 将暂停后数据(当前数据)保存起来–_resumeData = resumeData;
- 条件允许续传时,使用resumeData创建新的NSURLSessionTask
NSURLSessionUploadTask
在 NSURLSession 中,文件上传主要使用两种方式:
1 | - (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)request fromFile:(NSURL *)fileURL; |
总结
- NSURLSession 是iOS7后出来的替代 NSURLConnection 的API;
- NSURLSession 通过绑定一个 delegate 在一个网络会话的生命周期里调用某些事件;
- NSURLSession 对象是线程安全的;
- NSURLSession 默认使用系统提供的delegate,并适当的使用现有的代码使用;
- NSURLSession 通过创建 NSURLSessionTask 代表资源被加载的任务,类似 NSURLConnection对象,但相比有更多可控制和定制的 delegate 模型;
- NSURLSessionTask 对象创建后是处于挂起状态,只有发-resume消息才会执行;
- NSURLSessionTask 的子类 在加载 Data 和 文件下载的使用上有所不同;
- NSURLSessionDataTask 接收到资源时会回调 RLSession:dataTask:didReceiveData: 代理method;
- NSURLSessionUploadTask 与 NSURLSessionDataTask 的构造方法不同,他需求显示的引用file或data object;
- NSURLSessionDownloadTask 会直接把response data写入到临时文件,网络会话结束后,delegate 会发送一个 URLSession:downloadTask:didFinishDownloadingToURL: 消息来处理下载文件,如果中途取消则会生成一个Blob Data以便下次恢复下载;
- 从iOS9开始,使用NSURLSessionStream可以通过一个给定的主机和端口直接建立TCP/IP连接;
NSURLSession的优点
后台上传和下载:
只需在创建NSURLSession的时候配置一个选项,就能得到后台网络的所有好处;能够暂停和恢复网络操作:
使用NSURLSession API能够暂停,停止,恢复所有的网络任务,再也完全不需要子类化NSOperation;可配置的容器:
对于NSURLSession里面的requests来说,每个NSURLSession都是可配置的容器。举个例来说,假如你需要设置HTTP header选项,你只用做一次,session里面的每个request就会有同样的配置。提高认证处理:
认证是在一个指定的连接基础上完成的。在使用NSURLConnection时,如果发出一个访问,会返回一个任意的request。此时,你就不能确切的知道哪个request收到了访问。而在NSURLSession中,就能用代理处理认证。丰富的代理模式:
在处理认证的时候,NSURLConnection有一些基于异步的block方法,但是它的代理方法就不能处理认证,不管请求是成功或是失败。在NSURLSession中,可以混合使用代理和block方法处理认证。