iOS 网络编程:NSURLSession
NSURLSession类和相关的类提供很多API来下载HTTP的内容。这些API提供多种delegate协议来支持验证和执行后台下载任务。
1 URL Session 设计概念
Session中的任务行为依赖三件事:
- Session类型:在创建时,由configuration 对象决定;
- task类型:数据传输类型;
- session执行方式:有前台和后台两种方式。
1.1 Session类型(3种)
NSURLSession API提供三种类型的session,而这三种类型是在创建时由configuration对象决定:
1) Default sessions(默认模式):工作模式类似于原来的NSURLConnection,可以使用缓存的Cache,Cookie,鉴权;
2) Ephemeral sessions(及时模式):不能存储数据到磁盘,包括缓存的Cache,Cookie,鉴权;
3) Background sessions(后台模式):类似default模式,不同的是后台模式是拥有独立的进程来完成所有数据的传输。
1.2 Task类型(3种)
对于一个session,NSURLSession类支持三种任务类型:
1) Data任务:该任务是通过NSData对象来发送和接收,其目的经常是向服务器发送请求。
2) Download任务:该任务是以文件的形式查询数据,并且支持app不在运行状态时,在后台状态进行下载。
3) Upload任务:该任务是以文件的形式发送数据,并且支持app不在运行状态时,在后台进行上传。
1.3 后台传输设计
session还支持进行后台数据传输功能。但这种功能需要在创建session进行指定,同时它还有如下的限制:
- session必须提供delegate来响应事件;
- 仅支持HTTP和HTTPS协议,不支持自定义协议;
- 仅支持上传文件,而上传对象和字节流将在app退出时发送上传失败;
- 如果后台传输任务是app在后台进行初始化的,那么需要将configuration对象的configuration属性设置为true。
在IOS中,当后台任务传输完成或是需要认证,如果此时app不处于运行状态,那么IOS将自动重新启动该app程序,其中IOS将调用UIApplicationDelegate对象的application:handleEventsForBackgroundURLSession:completionHandler方法。
2 第一个程序
2.1 NSURLSession使用步骤
使用NSURLSession类来请求数据,可以按如下步骤进行:
a) 创建configuration对象,指定session需要的属性;
b) 创建session对象,并指定相应的configuration对象、选项和delegate对象;
c) 创建task对象,通过调用session相应的请求方法而创建,其中创建的task对象可以是NSURLSessionTask—NSURLSessionDataTask, NSURLSessionUploadTask, 或NSURLSessionDownloadTask的子类。
每个task对象在创建后都初始化为suspended状态,需要手动调用task对象的resume方法开始任务处理。
2.2 Xcode环境配置
- 打开 工程主目录下info.plist
- 增加属性字典 App Transport Security Settings
- 在这个属性下增加节点 Allow Arbitrary Loads, value 为 YES
图 1
2.3 源码说明
源码:Object-C
1 -(void) main
2 {
3 NSURLSession *session = [NSURLSession sharedSession]; //创建一个NSURLSession 对象
4 NSURL *url = [NSURL URLWithString:@"http://baidu.com"]; //创建一个URL连接
5 NSURLRequest *request = [NSURLRequest requestWithURL: url]; //创建请求对象
6
7 //创建任务
8 NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
9
10 NSString *string = [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding];
11
12 NSLog(string);
13 }];
14
15 [task resume]; //启动任务,即向服务器发送请求。
16 }
17 输出:
18 <html>
19 <meta http-equiv="refresh" content="0;url=http://www.baidu.com/">
20 </html>
3 创建session
3.1 配置(NSURLSessionConfiguration)
session的行为是由NSURLSessionConfiguration对象来指定的,因为session由三种类型,所以NSURLSessionConfiguration类就有三种初始化函数来创建三种类型的对象。
如下是初始化函数的声明:
+ (NSURLSessionConfiguration *)defaultSessionConfiguration; + (NSURLSessionConfiguration*)ephemeralSessionConfiguration; + (NSURLSessionConfiguration *)backgroundSessionConfigurationWithIdentifier:(NSString *)identifier |
3.2 创建(NSURLSession)
创建一个NSURLSession,系统提供了三个创建方法:
+ (NSURLSession *)sharedSession; + (NSURLSession *)sessionWithConfiguration:(NSURLSessionConfiguration *)configuration; +(NSURLSession*)sessionWithConfiguration:(NSURLSessionConfiguration*)configuration delegate: (id <NSURLSessionDelegate>)delegate delegateQueue:(NSOperationQueue *)queue; |
- 第一个是提供默认的session,不要配置;
- 第二个是使用粒度较低的configuration对象进行创建,系统默认创建一个新的OperationQueue处理Session的消息;
- 第三个同样使用configuration对象进行创建,同时可以设定回调的delegate(注意这个回调delegate会被强引用),并且可以设定delegate在哪个OperationQueue回调,如果我们将其设置为[NSOperationQueue mainQueue]就能在主线程进行回调非常的方便。
如下例子:
1 /* Create some configuration objects. */
2 NSURLSessionConfiguration *backgroundConfigObject = [NSURLSessionConfiguration backgroundSessionConfiguration: @"myBackgroundSessionIdentifier"];
3 NSURLSessionConfiguration *defaultConfigObject = [NSURLSessionConfiguration defaultSessionConfiguration];
4 NSURLSessionConfiguration *ephemeralConfigObject = [NSURLSessionConfiguration ephemeralSessionConfiguration];
5
6 /* Create a session for each configurations. */
7 NSURLSession *defaultSession = [NSURLSession sessionWithConfiguration: defaultConfigObject delegate: self delegateQueue: [NSOperationQueue mainQueue]];
8 NSURLSession *backgroundSession = [NSURLSession sessionWithConfiguration: backgroundConfigObject delegate: self delegateQueue: [NSOperationQueue mainQueue]];
9 NSURLSession *ephemeralSession = [NSURLSession sessionWithConfiguration: ephemeralConfigObject delegate: self delegateQueue: [NSOperationQueue mainQueue]];
4 创建task
在NSURLSession API中,实现与服务器进行数据的交互是通过Task(任务)完成,即Task有data、Download和upload类型。
4.1 直接请求
直接请求方式是指可以简单调用NSURLSession指定的方法进行数据下载或上传,而无需再实现Delegate协议,因为IOS框架默认已经帮忙实现了Delegate协议。
由于NSURLSession有三种Task类型:data任务、upload任务和download任务,并且三种任务都是异步执行的。所以提供三种类型的交互方法,其中每种方式都是使用异步方法,当任务完成后,调用相应的回调函数。
表 11 三种任务类型创建方法
Task类型 |
方法 |
语义 |
Data Tasks |
- dataTaskWithURL: |
创建一个GET方法的HTTP请求,请求的地址由URL参数指定。 |
- dataTaskWithURL:completionHandler: |
这也是创建一个GET请求,但是当请求完成后,会调用completionHandler函数块。 |
|
- dataTaskWithRequest: |
创建一个HTTP请求,请求的其它更多参数可以由NSMutableURLRequest对象指定,HTTP请求的method、timeoutInterval和URL等信息。 |
|
- dataTaskWithRequest:completionHandler: |
类似上述方法,不同的是有完成回调函数。 |
|
Download Tasks |
- downloadTaskWithURL: |
创建一个下载url路径的任务 |
- downloadTaskWithURL:completionHandler: |
||
- downloadTaskWithRequest: |
创建一个下载NSURLRequest 的任务 |
|
- downloadTaskWithRequest:completionHandler: |
||
- downloadTaskWithResumeData: |
创建一个下载NSData的任务 |
|
- downloadTaskWithResumeData:completionHandler: |
||
Upload Tasks |
- uploadTaskWithRequest:fromData: |
创建一个由NSURLRequest指定的上传任务,所上传的数据存放在 NSData对象中 |
- uploadTaskWithRequest:fromData:completionHandler: |
||
- uploadTaskWithRequest:fromFile: |
创建一个由NSURLRequest指定的上传任务,所上传的数据存放在 NSURL路径中 |
|
- uploadTaskWithRequest:fromFile: completionHandler: |
||
- uploadTaskWithStreamedRequest: |
创建一个由NSURLRequest指定的上传任务,所上传的数据由如下的委托方法提供:URLSession:task:needNewBodyStream: |
注意:使用系统提供的默认delegete,进行下载和上传功能是受限制的。
如:
1 -(void) system_provided_delegates
2 {
3 NSURLSessionConfiguration *defaultConfigObject = [NSURLSessionConfiguration defaultSessionConfiguration];
4 NSURLSession *delegateFreeSession = [NSURLSession sessionWithConfiguration: defaultConfigObject delegate: nil delegateQueue: [NSOperationQueue mainQueue]];
5
6 NSURLSessionDataTask *task = [delegateFreeSession dataTaskWithURL: [NSURL URLWithString: @"http://www.example.com/"]
7 completionHandler:^(NSData *data, NSURLResponse *response,
8 NSError *error) {
9 NSLog(@"Got response %@ with error %@.\n", response, error);
10 }] ;
11 [task resume];
12 }
4.2 委托请求
由于使用系统默认的Delegate方式,进行下载和上传只能控制部分内容,若需要对任务进行更多的控制,则需要实现自定义Delegate。如果使用自定义的Delegate对象来处理数据,那么与服务器的交互都可以在Delegate协议方法内完成。其中NSURLSession提供的Delegate协议有四个:
表 12
协议 |
功能 |
NSURLSessionDelegate |
定义了session级别的事件; |
NSURLSessionTaskDelegate |
定义了一些方法来操作task级别的事件包括所有的 task类型; |
NSURLSessionDataDelegate |
定义了一些方法来操作task级别事件,特别是data 和upload 任务; |
NSURLSessionDownloadDelegate |
定义了一些方法来操作task级别事件,特别是download 任务。 |
那么至少需要实现NSURLSessionDataDelegate协议如下的两个方法:
- URLSession:dataTask:didReceiveData: 告诉delegate已经接收了一部分数据;
- URLSession:task:didCompleteWithError:告诉delegate已经完成了数据传输任务。
如下是实现了自定定义delegate协议的类:
1 @interface sesionCustomDelegate : NSURLSession <NSURLSessionDataDelegate>
2 -(void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error;
3 -(void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data;
4 @end
5 @implementation sesionCustomDelegate
6 -(void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
7 {
8 printf("didCompleteWithError\n");
9 }
10 -(void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data
11 {
12 printf("didReceiveData\n");
13 }
14 @end
如下是自定义类的使用方式:
1 -(void) Fetching_custom_delegate
2 {
3 sesionCustomDelegate *customSession = [[sesionCustomDelegate alloc] init];
4 NSURLSessionConfiguration *defaultConfigObject = [NSURLSessionConfiguration defaultSessionConfiguration];
5
6 NSURLSession *defaultSession = [NSURLSession sessionWithConfiguration: defaultConfigObject delegate: customSession delegateQueue: [NSOperationQueue mainQueue]];
7
8 NSURL *url = [NSURL URLWithString: @"http://www.example.com/"];
9 NSURLSessionDataTask *dataTask = [defaultSession dataTaskWithURL: url];
10
11 [dataTask resume];
12 }
4.3 开始任务
通过调用NSURLSession 对象来创建任务后,将返回NSURLSessionTask对象或者其子类(NSURLSessionDataTask, NSURLSessionUploadTask, 和NSURLSessionDownloadTask ),此时的NSURLSessionTask对象还处于挂起状态,需要手动调用其resume方法来启动任务,在调用resume方法后立即返回,即不需等待任务完成。
其中NSURLSessionTask对象拥有多种状态:Running、Suspended、Canceling和Completed四种状态。
5 Downloading文件
5.1 协议方法
在高层级别上,下载数据与请求数据类似,应用程序中应该实现NSURLSessionDownloadDelegate协议的如下方法:
- URLSession:downloadTask:didFinishDownloadingToURL: 通知下载任务已经完成,其中下载任务只是下载到一个暂时的位置。而在此方法返回之前,需要将该文件移动到一个永久的目录下,或者读起文件的内容。
- URLSession:downloadTask:didWriteData:totalBytesWritten:totalBytesExpectedToWrite: 用于获取当前下载任务的状态。
- URLSession:downloadTask:didResumeAtOffset:expectedTotalBytes: 通知app已经将下载失败的任务重启成功,只是通知重新开始下载了,并不是已经下载完成了。
- URLSession:task:didCompleteWithError: 通知app任务下载失败。
5.2 下载任务
由于app在运行过程中会被挂起、暂停或是退出,那么不同的session模式,对正在下载的任务有不同的处理方式:
- 如果创建的是后台session,那么当app不在运行状态,那么它将继续下载;
- 如果创建的标准或是及时session,那么当app重新启动,必须重新开始下载。
上述是IOS强制关闭下载任务的情况,也可以利用NSURLSessionDownloadTask对象和NSURLSession对象提供一些功能来手动暂停和重启下载任务。
- cancelByProducingResumeData: 该方法是NSURLSessionDownloadTask类中的方法,通过该方法能够手动暂停正在下载的任务;
- downloadTaskWithResumeData: 该方法是NSURLSession类中的方法,通过该方法能够重启被暂停的任务。
如下是实现了下载协议的类:
1 @interface DownloadCustomDelegate : NSObject <NSURLSessionDownloadDelegate>
2 ……
3 @end
4
5 @implementation DownloadCustomDelegate
6 -(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location
7 {
8 printf("didFinishDownloadingToURL\n");
9 }
10
11 -(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite
12 {
13 NSLog(@"Session %@ download task %@ wrote an additional %lld bytes (total %lld bytes) out of an expected %lld bytes.\n",
14 session, downloadTask, bytesWritten, totalBytesWritten, totalBytesExpectedToWrite);
15 }
16
17 -(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didResumeAtOffset:(int64_t)fileOffset expectedTotalBytes:(int64_t)expectedTotalBytes
18 {
19 NSLog(@"Session %@ download task %@ resumed at offset %lld bytes out of an expected %lld bytes.\n",
20 session, downloadTask, fileOffset, expectedTotalBytes);
21 }
22
23 -(void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
24 {
25 printf("didCompleteWithError\n");
26 }
27 @end
如下是调用自定义delegate的类:
1 -(void) Downloading_Files
2 {
3 DownloadCustomDelegate *downloadCustomDelegate = [[DownloadCustomDelegate alloc] init];
4
5 NSURLSessionConfiguration *backgroundConfigObject = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:@"myBackgroundSessionIdentifier"];
6
7 NSURLSession *backgroundSession = [NSURLSession sessionWithConfiguration: backgroundConfigObject delegate: downloadCustomDelegate delegateQueue: [NSOperationQueue mainQueue]];
8
9 NSURL *url = [NSURL URLWithString: @"https://developer.apple.com/library/ios/documentation/Cocoa/Reference/"
10 "Foundation/ObjC_classic/FoundationObjC.pdf"];
11
12 NSURLSessionDownloadTask *downloadTask = [backgroundSession downloadTaskWithURL: url];
13 [downloadTask resume];
14 }
6 Uploading内容
应用程序可以通过HTTP的POST请求,将数据内容封装在HTTP的请求体中,从而上传到服务器中。其中支持的上传方式有如下三种:
1) NSData对象
2) File
3) Stream
6.1 使用NSData对象
为了将NSData对象上传到服务器,应该调用NSURLSession对象的uploadTaskWithRequest:fromData: 方法或是uploadTaskWithRequest:fromData:completionHandler:方法,从而创建上传任务,并且将NSData对象传递给fromData参数。
6.2 使用File
为了将File上传到服务器,需要调用NSURLSession对象的uploadTaskWithRequest:fromFile: 方法或是 uploadTaskWithRequest:fromFile:completionHandler: 方法,从而创建上传任务,并且给fromFile参数传递是File文件的URL路径。
6.3 使用Stream
同样为了将Stream上传到服务器,需要调用NSURLSession对象的uploadTaskWithStreamedRequest: 方法,从而创建上传任务,而上传的内容是存放在NSURLRequest对象相关的字节流中。
7 参考文献
[1] URL Session programming guide。
iOS 网络编程:NSURLSession的更多相关文章
- iOS网络编程模型
iOS网络编程层次结构也分为三层: Cocoa层:NSURL,Bonjour,Game Kit,WebKit Core Foundation层:基于 C 的 CFNetwork 和 CFNetServ ...
- IOS网络编程——第三方类库
IOS网络编程——第三方类库 目录 概述 ASIHttpRequest AFNetworking 其他 概述 ASIHttpRequest AFNetworking 其他
- IOS网络编程:HTTP
IOS网络编程:HTTP HTTP定义了一种在服务器和客户端之间传递数据的途径. URL定义了一种唯一标示资源在网络中位置的途径. REQUESTS 和 RESPONSES: 客户端先建立一个TCP连 ...
- iOS网络编程笔记——Socket编程
一.什么是Socket通信: Socket是网络上的两个程序,通过一个双向的通信连接,实现数据的交换.这个双向连路的一端称为socket.socket通常用来实现客户方和服务方的连接.socket是T ...
- iOS 网络编程模式总结
IOS 可以采用三类api 接口进行网络编程,根据抽象层次从低到高分别为socket方式.stream方式.url 方式. 一 .socket 方式 IOS 提供的socket 方式的网络编程接口为C ...
- iOS网络编程
今天的重点是UIWebView.NSURLSession.JSon. 网络编程联网准备:1.在Info.plist中添加AppTransportSecurity类型Dictionary:2.在AppT ...
- 浅谈iOS网络编程之一入门
计算机网络,基本上可以抽象是端的通信.实际在通讯中会用到不同的设备,不同的硬件中,为了能友好的传输信息,那么建立一套规范就十分必要了.先来了解一些基本概念 了解网络中传输的都是二进制数据流. 2.了 ...
- iOS 网络编程:socket
@import url(http://i.cnblogs.com/Load.ashx?type=style&file=SyntaxHighlighter.css);@import url(/c ...
- ios网络编程(入门级别)-- 基础知识
在学习ios的过程中,停留在UI控件很长时间,现在正在逐步的接触当中!!!!!!在这个过程中,小编学到了一些关于网络编程知识,并且有感而发,在此分享一下: 关于网络请求的重要性我想不用多说了吧!!!对 ...
- iOS:网络编程的第三方框架:AFNetworking、SDWebImage
网络编程第三方框架:AFNetworking.SDWebImage 介绍:这些框架是开源的,经过前人的封装.改进,成为使用次数很多的一个性能好的源代码框架,只需要将它导入项目中,就可以使用.因此,在做 ...
随机推荐
- 关于app transfer之后的开发
原文 http://blog.csdn.net/donghong2008/article/details/38020855 网络上有很多开发者提问怎么转让App并想知道具体的流程.实际上Appsto ...
- Read ListViewItem content from another process z
Normal Windows GUI applications work with messages that are sent to a window or control and the cont ...
- HDU-5373 The shortest problem
The shortest problem http://acm.hdu.edu.cn/showproblem.php?pid=5373 Time Limit: 3000/1500 MS (Java/O ...
- 为EF DbContext生成的实体添加注释(T5模板应用)[转]
1 先加上类注释 找到这行代码WriteHeader(codeStringGenerator, fileManager): 在它下面加上我们的代码: string summary=string.Emp ...
- kafka的安装和使用
简单说kafka是一个高吞吐的分部式消息系统,并且提供了持久化. kafka的架构 • producer:消息生存者• consumer:消息消费者• broker:kafka集群的server,负责 ...
- Html笔记(十)XHTML XML
XHTML 是可扩展的超文本标记语言(Extensible HyperText Markup Language). XHTML 是 w3c 组织在2000年的时候为了增强HTML推出的,本来是想替代H ...
- 关于VNC黑屏的问题
注意: 1.vncserver启动后生成的ID号(1,2,3)要和VNCview里面填入的 ip:ID要保持一致 不然看到的就是黑屏 比如:vncserver启动后 产生: localhost.lo ...
- Spring笔记之(一)初探
对spring框架的学习我是从模拟它的简单实现开始,这样也易于领悟到它的整个框架结构,以下是简单实现的代码: 配置文件:spring.xml <?xml version="1.0&qu ...
- 算法导论学习-Dynamic Programming
转载自:http://blog.csdn.net/speedme/article/details/24231197 1. 什么是动态规划 ------------------------------- ...
- (android 源码下开发应用程序) 如何在 Android 各 level ( 包含 user space 與 kernel space ) 使用dump call stack的方法
http://janbarry0914.blogspot.com/2014/07/androiddump-call-stack.html dump call stack [文章重點] 了解 Andro ...