iOS | NSURLSession 介绍与使用

简介

NSURLSession 是苹果公司在2013的 WWDC大会上随 iOS7 一起发布的,是 NSURLConnection 的继任者。 NSURLConnection在iOS9 之后也被宣布弃用。目前 AFNetworking、SDWebImage 等知名类库也都更新使用了 NSURLSession 。

NSURLSession的优势:

  • 针对不同的网络请求任务提供了专门的解决方案;
  • 支持任务取消、暂停、恢复、支持应用程序后台下载;
  • 安全身份验证方案;
  • 下载操作内存优化;
  • 更灵活请求的配置。

使用

首先我们看下NSURLSession最简单的使用,通过下面代码就可以实现了基本的网络请求了。

    NSURL *url = [NSURL URLWithString:@"http://....."];
    NSURLSession *session = [NSURLSession sharedSession];
    NSURLSessionDataTask *task = [session dataTaskWithURL:url  completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
       // handle  response
    }];
    [task resume];

所有的NSURLSession 网络请求基本遵循以下几个步骤:

  1. 获取NSURLSession对象
  2. 通过session对象创建 task 任务
  3. 执行 task(task 默认是挂起的,通过resume执行)

NSURLSession

NSURLSession继承NSObject,提供了3种会话模式,主要通过 NSURLSessionConfiguration来进行初始化,同时还可以设置 dalegate 来进行下载过程监听

+ (NSURLSession *)sharedSession; //共享的会话,该会话使用全局的Cache,Cookie和证书,无法进行 Configuration配置
+ (NSURLSession *)sessionWithConfiguration:(NSURLSessionConfiguration *)configuration; // 通过 NSURLSessionConfiguration初始化
+ (NSURLSession *)sessionWithConfiguration:(NSURLSessionConfiguration *)configuration delegate:(nullable id <NSURLSessionDelegate>)delegate delegateQueue:(nullable NSOperationQueue *)queue;  // 通过 NSURLSessionConfiguration、 delegate 、队列初始化

接下来我们看下NSURLSessionConfiguration的3种配置,他们是和NSURLSession的会话模式一一对应的

@property (class, readonly, strong) NSURLSessionConfiguration *defaultSessionConfiguration;
@property (class, readonly, strong) NSURLSessionConfiguration *ephemeralSessionConfiguration;
+ (NSURLSessionConfiguration *)backgroundSessionConfigurationWithIdentifier:(NSString *)identifier API_AVAILABLE(macos(10.10), ios(8.0), watchos(2.0), tvos(9.0));
  • defaultSessionConfiguration 默认配置使用的是持久化的硬盘缓存,存储证书到用户钥匙链。存储cookie到shareCookie。
  • ephemeralSessionConfiguration 这个配置中不会对缓存,Cookie 和证书进行持久性的存储。
  • + backgroundSessionConfigurationWithIdentifier:(NSString *)identifier 它会返回一个后台 session。可以在应用程序挂起,退出或者崩溃的情况下运行上传和下载任务。

另外: NSURLSessionConfiguration是提供了很多属性,从 指定可用网络,到 cookie,安全性,缓存策略,再到使用自定义协议,启动事件的设置,以及用于移动设备优化的几个新属性,可以找到几乎任何你想要进行配置的选项。

了解了 NSURLSession的模式以及配置,接下来我们看一下 NSURLSessionTask

NSURLSessionTask

NSURLsessionTask 是一个抽象类,其下有 3 个实体子类可以直使用用:NSURLSessionDataTaskNSURLSessionUploadTaskNSURLSessionDownloadTask。这 3 个子类封装了程序三个最基本的网络任务:获取数据,比如 JSON 或者 XML,上传文件和下载文件。

QQ140736@2x.png
  • NSURLSessionDataTask 可以用来处理一般的网络请求
  • NSURLSessionDownloadTask 主要用于处理下载请求。
  • NSURLSessionUploadTask 用于处理上传请求。

当一个 NSURLSessionDataTask 完成时,它会带有相关联的数据,而一个 NSURLSessionDownloadTask 任务结束时,它会带回已下载文件的一个临时的文件路径。因为一般来说,服务端对于一个上传任务的响应也会有相关数据返回,所以 NSURLSessionUploadTask 继承自 NSURLSessionDataTask

所有的task 都是可以取消,暂停或者恢复的。当一个 download task 取消时,可以通过选项来创建一个恢复数据(resume data),然后可以传递给下一次新创建的 download task,以便继续之前的下载。

不同于直接使用alloc-init 初始化方法,task 是由一个 NSURLSession 创建的。每个 task 的构造方法都对应有或者没有 completionHandler block 的两个版本。如果 使用completionHandlerblock,代理回调将不会执行。

NSURLSessionTask工厂方法

NSURLSessionTask的工厂方法可以根据我们不同的需求返回不同的 task,这些task 不会立即运行,允许我们进一步的配置,然后可以使用 resume 方法来让它开始运行。

Datatask 可以通过 NSURLNSURLRequest 创建

NSURL *URL = [NSURL URLWithString:@"http://example.com"];
 NSURLRequest *request = [NSURLRequest requestWithURL:URL];

 NSURLSession *session = [NSURLSession sharedSession];
 NSURLSessionDataTask *task = [session dataTaskWithRequest:request
                                         completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
         // ...
     }];
 [task resume];

Uploadtask 的创建需要使用一个 request,另外加上一个要上传的 NSData 对象或者是一个本地文件的路径对应的 NSURL:

NSURL *URL = [NSURL URLWithString:@"http://example.com/upload"];
 NSURLRequest *request = [NSURLRequest requestWithURL:URL];
 NSData *data = ...;

 NSURLSession *session = [NSURLSession sharedSession];
 NSURLSessionUploadTask *uploadTask = [session uploadTaskWithRequest:request
                                                            fromData:data
                                                   completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
         // ...
     }];

 [uploadTask resume];

Download task 也需要一个 request或者Url,不同之处在于 completionHandler 这个 block。Datataskuploadtask 会在任务完成时一次性返回,但是 Download task是将数据一点点地写入本地的临时文件。所以在 completionHandler 这个 block 里,我们需要把文件从一个临时地址移动到一个永久的地址保存起来:

NSURL *URL = [NSURL URLWithString:@"http://example.com/file.zip"];
 NSURLRequest *request = [NSURLRequest requestWithURL:URL];

 NSURLSession *session = [NSURLSession sharedSession];
 NSURLSessionDownloadTask *downloadTask = [session downloadTaskWithRequest:request
                                                         completionHandler: ^(NSURL *location, NSURLResponse *response, NSError *error) {
        NSString *documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
        NSURL *documentsDirectoryURL = [NSURL fileURLWithPath:documentsPath];
        NSURL *newFileLocation = [documentsDirectoryURL URLByAppendingPathComponent:[[response URL] lastPathComponent]];
        [[NSFileManager defaultManager] copyItemAtURL:location toURL:newFileLocation error:nil];
    }];

 [downloadTask resume];

上面介绍了几种 NSURLSessionTask 的基本使用,都是通过completionHandler这个 block 来进行任务处理回调的,下来我们看看他的代理都有哪些,以及使用

NSURLSession代理

在我们请求过程中,如果想要监听网络操作过程中发生的事件,比如我们下载一个大文件的时候,如果要等到下载完成可能会需要比较长的事件,这时候更好的体验是能够提供一个下载进度。类似这样的事件我们就需要用到代理。

我们在使用三种 task 的任意一种的时候都可以指定相应的代理。NSURLSession 的代理对象结构如下:


QQ140750@2x.png
  • NSURLSessionDelegate 作为所有代理的基类,定义了网络请求最基础的代理方法。
  • NSURLSessionTaskDelegate - 定义了网络请求任务相关的代理方法。
  • NSURLSessionDownloadDelegate - 用于下载任务相关的代理方法,比如下载进度等等。
  • NSURLSessionDataDelegate - 用于普通数据任务和上传任务。

下面以下载为例,我们看下代码如何实现的

- (void)downloadtask{
    
    //  服务器地址
    NSURL *url = [NSURL URLWithString:@"http://d1.music.126.net/dmusic/NeteaseMusic_1.5.10_632_web.dmg"];
    //  创建 SessionConfiguration配置
    NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
    //  创建session实例并设置代理,用于监听下载
    NSURLSession *session = [NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:nil];
    //  创建 task
    self.task = [session downloadTaskWithURL:url];
    // 开始执行
    [self.task resume];
}

#pragma -mark NSURLSessionDownloadDelegate

/* 当下载任务完成下载时调用*/
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask
                              didFinishDownloadingToURL:(NSURL *)location{
    
    // location是一个temp文件下的临时路径,自己需要保存
    NSString *filePath = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:downloadTask.response.suggestedFilename];
    [[NSFileManager defaultManager] moveItemAtURL:location toURL:[NSURL fileURLWithPath:filePath] error:nil];
}

/* 定期发送通知委托下载进度. */
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask
                                           didWriteData:(int64_t)bytesWritten
                                      totalBytesWritten:(int64_t)totalBytesWritten
                              totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite{
    
    // 可在这里通过已写入的长度和总长度算出下载进度
    CGFloat progress = 1.0 * totalBytesWritten / totalBytesExpectedToWrite;
    NSLog(@"%f",progress);
    
}

/* 当下载已恢复时发送 */
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask
                                      didResumeAtOffset:(int64_t)fileOffset
                                     expectedTotalBytes:(int64_t)expectedTotalBytes{
}

/* 任务完成调用,查看是否成功 */
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error{

    if (!error){
        NSLog(@"下载完成");
    }else{
        NSLog(@"下载失败");
    }
}

通过实现NSURLSessionDownloadDelegate 协议,就可以实现接收下载完成的通知,下载进度变化的通知,以及下载进度恢复的通知。

总结

NSURLSession 除了我们介绍的支持 task 特性,NSURLSessionConfiguration 配置对象,以及代理之外还提供了很多关于网络请求的相关特性,比如缓存控制,Cookie 控制,HTTP 验证操作等等。总之 NSURLSession 简单的接口之外,也提供了强大的体系。

NSURLSession 相比 AFN这些第三方库来说也有一些不足,比如它没有提供很方便的自动数据类型转换。比如,AFN 中可以自动将服务端返回的 JSON 数据识别并解析出来,而使用 NSURLSession 则需要自己来完成。

后续有时间我会继续分析一下 NSURLSession在 AFN 中的使用!

参考链接:
https://developer.apple.com/documentation/foundation/nsurlsession
https://swiftcafe.io/2015/12/20/nsurlsession
http://www.cocoachina.com/ios/20180108/21778.html

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,294评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,493评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,790评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,595评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,718评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,906评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,053评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,797评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,250评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,570评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,711评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,388评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,018评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,796评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,023评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,461评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,595评论 2 350

推荐阅读更多精彩内容