1. 有的程序员老了,还没听过NSURLSession
  2. 有的程序员还嫩,没用过NSURLConnection
  3. 有的程序员很单纯,他只知道AFN.

NSURLConnection在iOS9被宣布弃用,NSURLSession从13年发展到现在,终于迎来了它独步江湖的时代.NSURLSession是苹果在iOS7后为HTTP数据传输提供的一系列接口,比NSURLConnection强大,坑少,好用.今天从使用的角度介绍下.

除了NSURLSession,文中还会频繁地出现NSURLSessionConfigurationNSURLSessionTask两个类.先认识一下,混个脸熟吧.

使用NSURLSession,拢共分两步:

  • 第一步 通过NSURLSession的实例创建task
  • 第二部 执行task

既然两步里面都出现了task,就先说说它吧.
NSURLSessionTask可以简单理解为任务:如数据请求任务,下载任务,上传任务and so on.我们使用的是他的子类们:

  • NSURLSessionTask(抽象类)

    • NSURLSessionDataTask

      • NSURLSessionUploadTask
    • NSURLSessionDownloadTask

从这几个子类的名字就可以大概猜出他们的作用了.接下来我们就从不同类型的任务出发,来使用session.

NSURLSessionDataTask

字面上看是和数据相关的任务,但其实dataTask完全可以胜任downloadTask和uploadTask的工作.这可能也是我们使用最多的task种类.

简单GET请求

如果请求的数据比较简单,也不需要对返回的数据做一些复杂的操作.那么我们可以使用带block

  1.  
  1. // 快捷方式获得session对象
  2. NSURLSession *session = [NSURLSession sharedSession];
  3. NSURL *url = [NSURL URLWithString:@"http://www.daka.com/login?username=daka&pwd=123"];
  4. // 通过URL初始化task,在block内部可以直接对返回的数据进行处理
  5. NSURLSessionTask *task = [session dataTaskWithURL:url
  6. completionHandler:^(NSData *data, NSURLResponse *response, NSError error) {
  7. NSLog(@"%@", [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil]);
  8. }];
  9.  
  10. // 启动任务
  11. [task resume];

Tips:

  • 所有类型的task都要调用resume方法才会开始进行请求.

简单POST请求

POST和GET的区别就在于request,所以使用session的POST请求和GET过程是一样的,区别就在于对request的处理.

  1. NSURL *url = [NSURL URLWithString:@"http://www.daka.com/login"];
  2. NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
  3. request.HTTPMethod = @"POST";
  4. request.HTTPBody = [@"username=daka&pwd=123" dataUsingEncoding:NSUTF8StringEncoding];
  5.  
  6. NSURLSession *session = [NSURLSession sharedSession];
  7. // 由于要先对request先行处理,我们通过request初始化task
  8. NSURLSessionTask *task = [session dataTaskWithRequest:request
  9. completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { NSLog(@"%@", [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil]); }];
  10. [task resume];

NSURLSessionDataDelegate代理方法

NSURLSession提供了block方式处理返回数据的简便方式,但如果想要在接收数据过程中做进一步的处理,仍然可以调用相关的协议方法.NSURLSession的代理方法和NSURLConnection有些类似,都是分为接收响应、接收数据、请求完成几个阶段.

  1. // 使用代理方法需要设置代理,但是session的delegate属性是只读的,要想设置代理只能通过这种方式创建session
  2. NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]
  3. delegate:self
  4. delegateQueue:[[NSOperationQueue alloc] init]];
  5.  
  6. // 创建任务(因为要使用代理方法,就不需要block方式的初始化了)
  7. NSURLSessionDataTask *task = [session dataTaskWithRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www.daka.com/login?userName=daka&pwd=123"]]];
  8.  
  9. // 启动任务
  10. [task resume];
  11.  
  12. //对应的代理方法如下:
  13.  
  14. // 1.接收到服务器的响应
  15. - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler {
  16. // 允许处理服务器的响应,才会继续接收服务器返回的数据
  17. completionHandler(NSURLSessionResponseAllow);
  18. }
  19.  
  20. // 2.接收到服务器的数据(可能调用多次)
  21. - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data {
  22. // 处理每次接收的数据
  23. }
  24.  
  25. // 3.请求成功或者失败(如果失败,error有值)
  26. - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error {
  27. // 请求完成,成功或者失败的处理
  28. }

Tips:

关键点在代码注释里面都有提及,重要的地方再强调一下:

  • 如果要使用代理方法,需要设置代理,但从NSURLSession的头文件发现session的delegate属性是只读的.因此设置代理要通过session的初始化方法赋值:sessionWithConfiguration:delegate:delegateQueue:其中:

    • configuration参数(文章开始提到的)需要传递一个配置,我们暂且使用默认的配置[NSURLSessionConfiguration defaultSessionConfiguration]就好(后面会说下这个配置是干嘛用的);
    • delegateQueue参数表示协议方法将会在哪个队列(NSOperationQueue)里面执行.
  • NSURLSession在接收到响应的时候要先对响应做允许处理:completionHandler(NSURLSessionResponseAllow);,才会继续接收服务器返回的数据,进入后面的代理方法.值得一提的是,如果在接收响应的时候需要对返回的参数进行处理(如获取响应头信息等),那么这些处理应该放在前面允许操作的前面.

NSURLSessionDownloadTask

文件下载可以使用NSURLSessionDownloadTask这个子类.

简单下载

NSURLSessionDownloadTask同样提供了通过NSURL和NSURLRequest两种方式来初始化并通过block进行回调的方法.下面以NSURL初始化为例:

  1. NSURLSession *session = [NSURLSession sharedSession];
  2. NSURL *url = [NSURL URLWithString:@"http://www.daka.com/resources/image/icon.png"] ;
  3. NSURLSessionDownloadTask *task = [session downloadTaskWithURL:url completionHandler:^(NSURL *location, NSURLResponse *response, NSError *error) {
  4. // location是沙盒中tmp文件夹下的一个临时url,文件下载后会存到这个位置,由于tmp中的文件随时可能被删除,所以我们需要自己需要把下载的文件挪到需要的地方
  5. NSString *path = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:response.suggestedFilename];
  6. // 剪切文件
  7. [[NSFileManager defaultManager] moveItemAtURL:location toURL:[NSURL fileURLWithPath:path] error:nil];
  8. }];
  9. // 启动任务
  10. [task resume];

Tips:

  • 需要注意的就是需要将下载到tmp文件夹的文件转移到需要的目录.原因在代码中已经贴出.
  • response.suggestedFilename是从相应中取出文件在服务器上存储路径的最后部分,如数据在服务器的url为http://www.daka.com/resources/image/icon.png, 那么其suggestedFilename就是icon.png.

NSURLSessionDownloadDelegate代理方法

同样的,downloadTask也提供了配套的代理方法

  1. // 每次写入调用(会调用多次)
  2. - (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite {
  3. // 可在这里通过已写入的长度和总长度算出下载进度
  4. CGFloat progress = 1.0 * totalBytesWritten / totalBytesExpectedToWrite; NSLog(@"%f",progress);
  5. }
  6.  
  7. // 下载完成调用
  8. - (void)URLSession:(NSURLSession *)session
  9. downloadTask:(NSURLSessionDownloadTask *)downloadTask
  10. didFinishDownloadingToURL:(NSURL *)location {
  11. // location还是一个临时路径,需要自己挪到需要的路径(caches下面)
  12. NSString *filePath = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:downloadTask.response.suggestedFilename];
  13. [[NSFileManager defaultManager] moveItemAtURL:location toURL:[NSURL fileURLWithPath:filePath] error:nil];
  14. }
  15.  
  16. // 任务完成调用
  17. - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error {
  18.  
  19. }

NSURLSessionUploadTask

在NSURLSession中,文件上传方式主要有以下两种:

  1. NSURLSessionUploadTask *task =[[NSURLSession sharedSession] uploadTaskWithRequest:request
  2. fromFile:fileName
  3. completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {}];

  4. [self.session uploadTaskWithRequest:request
  5. fromData:body
  6. completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
  7. NSLog(@"-------%@", [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil]);
  8. }];

处于安全性考虑,通常我们会使用POST方式进行文件上传,所以较多使用第二种方式.

但是,NSURLSession并没有为我们提供比NSURLConnection更方便的文件上传方式.方法中body处的参数需要填写request的请求体(http协议规定格式的大长串).因为你有90%的可能性用了AFNetworking,即使是自己写的应该也是copy,所以代码就不贴了我们只说方法呵呵哒.

断点下载

NSURLSessionDownloadTask提供了与断点下载相关的几个方法:

  1. // 使用这种方式取消下载可以得到将来用来恢复的数据,保存起来
  2. [self.task cancelByProducingResumeData:^(NSData *resumeData) {
  3. self.resumeData = resumeData;
  4. }];
  5.  
  6. // 由于下载失败导致的下载中断会进入此协议方法,也可以得到用来恢复的数据
  7. - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
  8. {
  9. // 保存恢复数据
  10. self.resumeData = error.userInfo[NSURLSessionDownloadTaskResumeData];
  11. }
  12.  
  13. // 恢复下载时接过保存的恢复数据
  14. self.task = [self.session downloadTaskWithResumeData:self.resumeData];
  15. // 启动任务
  16. [self.task resume];

以目前我对NSURLSession的理解这种断点下载只支持应用内断点,如果程序在下载过程中途关闭,则不能恢复下载.(暂时对NSURLSession理解还不全面,不敢妄下断论,如有不妥简友们可以沟通下)

其他

此外,task们自身有都拥有下面几个方法

  1. - (void)suspend;
  2. - (void)resume;
  3. - (void)cancel;

suspend可以让当前的任务暂停
resume方法不仅可以启动任务,还可以唤醒suspend状态的任务
cancel方法可以取消当前的任务,你也可以向处于suspend状态的任务发送cancel消息,任务如果被取消便不能再恢复到之前的状态.

NSURLSessionConfiguration

简单地说,就是session的配置信息.如:

  1. NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
  2. // 超时时间
  3. config.timeoutIntervalForRequest = ;
  4. // 是否允许使用蜂窝网络(后台传输不适用)
  5. config.allowsCellularAccess = YES;
  6. // 还有很多可以设置的属性

有没有发现我们使用的Configuration都是默认配置:[NSURLSessionConfiguration defaultSessionConfiguration],其实它的配置有三种类型:

  1. + (NSURLSessionConfiguration *)defaultSessionConfiguration;
  2. + (NSURLSessionConfiguration *)ephemeralSessionConfiguration;
  3. + (NSURLSessionConfiguration *)backgroundSessionConfigurationWithIdentifier:(NSString *)identifier

表示了NSURLSession几种不同的工作模式.
默认的配置会将缓存存储在磁盘上,第二种瞬时会话模式不会创建持久性存储的缓存,第三种后台会话模式允许程序在后台进行上传下载工作.

除了支持任务的暂停和断点续传,我觉得NSURLSession之于NSURLConnection的最伟大的进步就是支持后台上传下载任务,这又是一个可以深入讨论的话题.但在这方面我还没有进行深入的研究,待后续了解之后另行开贴.

PS:AFNetWorking从2.0版本就有了基于NSURLSession的系列封装,感兴趣的童鞋自行前往了解.

文/CoderAO(简书作者)
原文链接:http://www.jianshu.com/p/fafc67475c73

[OC] NSURLSession的更多相关文章

  1. OC - 15.NSURLSession与NSURLSessionTask

    简介 NSURLSession也能完成网络请求 NSURLConnection在iOS9中不推荐使用,NSURLSession是iOS9中推荐使用的网络请求方式 NSURLSession需要与NSUR ...

  2. iOS开发——网络篇——NSURLSession,下载、上传代理方法,利用NSURLSession断点下载,AFN基本使用,网络检测,NSURLConnection补充

    一.NSURLConnection补充 前面提到的NSURLConnection有些知识点需要补充 NSURLConnectionDataDelegate的代理方法有一下几个 - (void)conn ...

  3. NSURLConnection、NSURLSession

    NSURLConnection   1.准备网络资源地址:URL 注意:由于URL支持26个英文字母,数字和少数的几个特殊字符. 因此对于URL中包含非标准URL的字符,需要进行编码. iOS提供了函 ...

  4. (一二七)NSURLSession的基本用法 下载与数据获取

    简介 NSURLSession是苹果官方提供的一系列网络接口库,使用他们可以轻松实现下载和数据获取等任务.在上一篇文章中,我们介绍了使用NSURLConnection下载文件和断点续传的功能,实现起来 ...

  5. 24、JSON与OC互相转化

    一. JSON: 1. 01.JSON是一种轻量级的数据格式,一般用于数据交互 02.服务器返回给客户端的数据,一般都是JSON格式活着XML格式(文件下载除外) JSON的格式很像OC中的字典和数组 ...

  6. swift3.0:NSURLSession的使用

    一.说明 NSURLSession是OC中的会话类,在Swift中变成URLSession类,它们的实现方式是一样的,下面的示例就Swift语法进行讲解和介绍. 二.介绍: URLSession 类支 ...

  7. 百度智能(文本识别),API传图OC代码与SDK使用

    百度智能中的文本识别中的身份证识别,有API方式和SDK方式 API方式 百度智能(文本识别),百度API传图没有提供OC的示例,这里提供一下 - (void)OCTest:(NSString*)to ...

  8. iOS代码规范(OC和Swift)

    下面说下iOS的代码规范问题,如果大家觉得还不错,可以直接用到项目中,有不同意见 可以在下面讨论下. 相信很多人工作中最烦的就是代码不规范,命名不规范,曾经见过一个VC里有3个按钮被命名为button ...

  9. 用C语言封装OC对象(耐心阅读,非常重要)

    用C语言封装OC对象(耐心阅读,非常重要) 本文的主要内容来自这里 前言 做iOS开发的朋友,对OC肯定非常了解,那么大家有没有想过OC中NSInteger,NSObject,NSString这些对象 ...

随机推荐

  1. Android Studio 多个编译环境配置 多渠道打包 APK输出配置

    看完这篇你学到什么: 熟悉gradle的构建配置 熟悉代码构建环境的目录结构,你知道的不仅仅是只有src/main 开发.生成环境等等环境可以任意切换打包 多渠道打包 APK输出文件配置 需求 一般我 ...

  2. iframe用法

    <iframe src="http://caiyanli.top/" height="500"  width="500" frameb ...

  3. JavaScript var关键字、变量的状态、异常处理、命名规范等介绍

    本篇主要介绍var关键字.变量的undefined和null状态.异常处理.命名规范. 目录 1. var 关键字:介绍var关键字的使用. 2. 变量的状态:介绍变量的未定义.已定义未赋值.已定义已 ...

  4. docker for mac 学习记录

    docker基本命令 docker run -d -p 80:80 --name webserver nginx 运行容器并起别名 docker ps 展示目前启动的容器 docker ps -a 展 ...

  5. 15个关于Chrome的开发必备小技巧[译]

    谷歌Chrome,是当前最流行且被众多web开发人员使用的浏览器.最快六周就更新发布一次以及伴随着它不断强大的开发组件,使得Chrome成为你必备的开发工具.例如,在线编辑CSS,console以及d ...

  6. css样式之border

    border用法详解: 1.border-width 属性设置边框的宽度 可能的值:像素 2.border-style 属性设置边框的样式 可能的值:solid(直线),dashed(虚线),dott ...

  7. redis大幅性能提升之使用管道(PipeLine)和批量(Batch)操作

    前段时间在做用户画像的时候,遇到了这样的一个问题,记录某一个商品的用户购买群,刚好这种需求就可以用到Redis中的Set,key作为productID,value 就是具体的customerid集合, ...

  8. 编写简单的Makefile文件

    makefile中的编写内容如下: www:hello.c x.h gcc hello.c -o hello clean: rm hello www:hello.c  x.h 表示生成www这个文件需 ...

  9. 第13章 Linux日志管理

    1. 日志管理 (1)简介 在CentOS 6.x中日志服务己经由rsyslogd取代了原先的syslogd服务.rsyslogd日志服务更加先进,功能更多.但是不论该服务的使用,还是日志文件的格式其 ...

  10. Hbase安装和错误

    集群规划情况: djt1 active Hmaster djt2 standby Hmaster djt3 HRegionServer 搭建步骤: 第一步:配置conf/regionservers d ...