iOS知识梳理 | NSURLSession

梳理介绍 NSURLSession API及使用情况

NSURLSession

初印象

  • NSURLSession是NSURLConnection的替代API。它提供Session配置策略,以及下载数据过程中的回调Block或者Delegate
  • 在NSURLSession的生命周期,都对外暴露出Delegate方法,获取相应的事件处理
  • NSURLSession实例是线程安全的
  • NSURLSessionTask是个抽象类,有4个子类NSURLSessionDataTask、NSURLSessionUploadTask、NSURLSessionDownloadTask、NSURLSession,这样做是便于于语法区分数据和文件下载。NSURLSessionTask创建后需要发送-resume消息。

    • NSURLSessionDataTask普通的资源下载。通过
      URLSession:dataTask:didReceiveData:委托方法,获得序列化的数据,可在这里进行数据解析。
    • NSURLSessionUploadTask不同于NSURLSessionDataTask,它的实例需要引用要上传的文件或数据对象,然后通过-URLSession:task:needNewBodyStream:委托方法来提供上传数据。
    • NSURLSessionDownloadTask会先将下载的数据写入临时文件。完成后,将发送消息给代理方法URLSession:downloadTask:didFinishDownloadingToURL:,这里可以将此文件移动到其沙盒容器中的永久位置,或进行其他操作。当然还有很重要的断点续传。

      • NSURLSessionStreamTask主要是提供了基于NSURLSession的TCP/IP流的读写接口,代替NSInputStream和NSOutputStream
1
2
3
4
5
6
7
8
9
10
11
12
Delegate之间的关系如下:
--NSURLSessionDelegate
--NSURLSessionTaskDelegate
-- NSURLSessionDataDelegate
-- NSURLSessionDownloadDelegate
-- NSURLSessionStreamDelegate
Task关系如下:
--NSURLSessionTask
--NSURLSessionDataTask(方法列表与父类一样)
--NSURLSessionUploadTask
--NSURLSessionDownloadTask(新增取消方法:cancelByProducingResumeData方法)
--NSURLSessionStreamTask(新增读写方法)

这里只是翻译部分官方API的介绍,建议大家还是仔细阅读以下,一定有不少的收获。

网络请求

通过NSURLSessionTask进行,网络结果的Block跟请求函数在一起,比较清晰
NSURLSession 进行网络请求时,通过URL或者Request传入参数,生成NSURLSessionTask的实例,然后调用resume方法进行网络请求。

Get 请求

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
- (void)getWithsharedSession
{
// 获取默认 Session
NSURLSession *session = [NSURLSession sharedSession];
// 创建 URL
NSURL *url = [NSURL URLWithString:@"url"];
// 创建任务 task
NSURLSessionDataTask *task = [session dataTaskWithURL:url completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
// 获取数据后解析并输出
NSString *dataStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(@"%@",dataStr);
}];
// 启动任务
[task resume];
}

Post请求

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
- (void)postWithSharedSession
{
// 获取默认 Session
NSURLSession *session = [NSURLSession sharedSession];
// 创建 URL
NSURL *url = [NSURL URLWithString:@"url"];
// 创建 request
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
// 请求方法
request.HTTPMethod = @"POST";
// 请求体
request.HTTPBody = [@"username=1234&pwd=4321" dataUsingEncoding:NSUTF8StringEncoding];
// 创建任务 task
NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
// 获取数据后解析并输出
NSLog(@"%@",[NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil]);
}];
// 启动任务
[task resume];
}

通过NSURLSessionDelegate代理的方式,在代理函数中对网络结果进行处理。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
- (void)sessionDataDelegate
{
// 创建带有代理方法的自定义 session
NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[NSOperationQueue mainQueue]];
// 创建任务
NSURLSessionDataTask *task = [session dataTaskWithRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"url"]]];
// 启动任务
[task resume];
}
#pragma mark - NSURLSessionDelegate
// 1. 接收到服务器的响应
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler
{
NSLog(@"接收到服务器的响应");
// 必须设置对响应进行允许处理才会执行后面两个操作。
completionHandler(NSURLSessionResponseAllow);
}
// 2. 接收到服务器的数据(可能调用多次)
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data {
// 处理每次接收的数据
NSLog(@"接受到服务器的数据%s",__func__);
}
// 3. 请求成功或者失败(如果失败,error有值)
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error {
// 请求完成,成功或者失败的处理
NSLog(@"SessionTask %s",__func__);
}

除以上delegate方法之外,还有其他的代理方法,可以进行在需要的情况进行调用

NSURLSession与NSURLConnection

问题1 : NSURLSesstion和NSURLConnection 有什么联系(重点是区别)?

NSURLSession(>= iOS 7)是NSURLConnection(<= iOS9)的替代者,它是对NSURLConnection进行了重构优化后的新的网络接口。主要是将Connection进行拆分,拆成NSURLSession 、NSURLSessionTask、NSURLSessionConfiguration以及相应的Delegate,在实现NSURLConnection的原有功能同时,新增功能 :

  • 可以实现独立模块之间不受影响(配置模块可以共享)
  • 同时也持了请求的挂起及断点续传
  • 还新增了网络请求性能指标,NSURLSessionTaskTransactionMetrics(>= iOS10)

二者之间的关联
NSURLConnection主要废除的接口如下

1
2
3
4
5
6
7
8
9
10
- (nullable instancetype)initWithRequest:(NSURLRequest *)request delegate:(nullable id)delegate startImmediately:(BOOL)startImmediately NS_DEPRECATED(10_5, 10_11, 2_0, 9_0, "Use NSURLSession (see NSURLSession.h)") __WATCHOS_PROHIBITED;
- (nullable instancetype)initWithRequest:(NSURLRequest *)request delegate:(nullable id)delegate NS_DEPRECATED(10_3, 10_11, 2_0, 9_0, "Use NSURLSession (see NSURLSession.h)") __WATCHOS_PROHIBITED;
+ (nullable NSURLConnection*)connectionWithRequest:(NSURLRequest *)request delegate:(nullable id)delegate NS_DEPRECATED(10_3, 10_11, 2_0, 9_0, "Use NSURLSession (see NSURLSession.h)") __WATCHOS_PROHIBITED;
//异步请求
+ (void)sendAsynchronousRequest:(NSURLRequest*) request
queue:(NSOperationQueue*) queue
completionHandler:(void (^)(NSURLResponse* __nullable response, NSData* __nullable data, NSError* __nullable connectionError)) handler NS_DEPRECATED(10_7, 10_11, 5_0, 9_0, "Use [NSURLSession dataTaskWithRequest:completionHandler:] (see NSURLSession.h") __WATCHOS_PROHIBITED;
//同步请求
+ (nullable NSData *)sendSynchronousRequest:(NSURLRequest *)request returningResponse:(NSURLResponse * __nullable * __nullable)response error:(NSError **)error NS_DEPRECATED(10_3, 10_11, 2_0, 9_0, "Use [NSURLSession dataTaskWithRequest:completionHandler:] (see NSURLSession.h") __WATCHOS_PROHIBITED;

从中我们可以知道:

  • NSURLSession dataTaskWithRequest:completionHandler方法统一处理同步异步的请求结果
  • 通过NSURLSession创建的NSURLSessionTask进行资源加载时,包括下载和上传,这类似NSURLConnection对象提供的委托模型,但是 NSURLSessionTask对象初始化时处于暂停状态,需要在调用resume方法

NSURLSessionTask和NSURLConnection最大的相似之处在于它也负责数据中的加载,最大的不同之处在于所有的task共享其创造者NSURLSession (这一公共委托者common delgate)

区别

  • 下载任务方式

    NSURLConnection下载文件时,先是将整个文件下载到内存,然后再写入到沙盒,如果文件比较大,就会出现内存暴涨的情况。

    NSURLSessionUploadTask下载文件,会默认下载到沙盒中的tem文件中,不会出现内存暴涨的情况,但是在下载完成后会把tem中的临时文件删除,需要在初始化任务方法时,在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进行断点下载更加便捷.

  • 配置信息
    >
    NSURLSession的构造方法(sessionWithConfiguration:delegate:delegateQueue)中有一个NSURLSessionConfiguration类的参数可以设置配置信息,其决定了cookie,安全和高速缓存策略,最大主机连接数,资源管理,网络超时等配置。NSURLConnection不能进行这个配置,相比较与NSURLConnection依赖与一个全局的配置对象,缺乏灵活性而言,NSURLSession有很大的改进了。(关于配置信息,后面会讲解到)

参考

http://www.jianshu.com/p/056b1817d25a