目录
- 使用现状
- 普通任务和上传
- 下载任务方式
- 请求方法的控制
- 断点续传的方式
- 配置信息
一 使用现状
NSURLSession是NSURLConnection 的替代者,在2013年苹果全球开发者大会(WWDC2013)随ios7一起发布,是对NSURLConnection进行了重构优化后的新的网络访问接口。从iOS9.0
开始, NSURLConnection中发送请求的两个方法已过期(同步请求,异步请求),初始化网络连接(initWithRequest: delegate:)的方法也被设置为过期,系统不再推荐使用,建议使用NSURLSession发送网络请求。
- 同步发送请求
// macos(10.3,10.11), ios(2.0,9.0), tvos(9.0,9.0)
+ (NSData *)sendSynchronousRequest:(NSURLRequest *)request
returningResponse:(NSURLResponse **)response
error:(NSError **)error;
- 异步发送请求
// macos(10.7,10.11), ios(5.0,9.0), tvos(9.0,9.0)
+ (void)sendAsynchronousRequest:(NSURLRequest*) request
queue:(NSOperationQueue*) queue
completionHandler:(void (^)(NSURLResponse*response, NSData*data, NSError* connectionError));
- 初始化网络连接
// macos(10.5,10.11), ios(2.0,9.0), tvos(9.0,9.0)
- (instancetype)initWithRequest:(NSURLRequest *)request delegate:(id)delegate startImmediately:(BOOL)startImmediately;
// macos(10.3,10.11), ios(2.0,9.0), tvos(9.0,9.0
- (instancetype)initWithRequest:(NSURLRequest *)request delegate:(id)delegate;
- 简单使用
- (void)useConnection {
// 1.请求路径
NSURL *url = [NSURL URLWithString:@"http://rap2api.taobao.org/app/mock/163155/gaoshilist"];
// 2.创建请求对象
NSURLRequest *request = [NSURLRequest requestWithURL:url];
// 3.异步发送请求
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[NSURLConnection sendAsynchronousRequest:request queue:queue completionHandler:^(NSURLResponse * response, NSData *data, NSError *connectionError) {
NSLog(@"length:%lu",(unsigned long)data.length);
}];
}
二 普通任务和上传
NSURLSession
针对下载/上传等复杂的网络操作提供了专门的解决方案,针对普通
、上传
和下载
分别对应三种不同的网络请求任务:NSURLSessionDataTask
, NSURLSessionUploadTask
和NSURLSessionDownloadTask.
。创建的task都是挂起状态
,需要resume
才能执行。
- 当服务器返回的数据较小时,NSURLSession与NSURLConnection执行普通任务的操作步骤没有区别。
- 执行上传任务时,NSURLSession与NSURLConnection一样同样需要设置POST请求的请求体进行上传。
普通任务NSURLSessionDataTask
实例代码
- (void)sessionDataTask {
// 1.请求路径
NSURL *url = [NSURL URLWithString:@"http://rap2api.taobao.org/app/mock/163155/gaoshilist"];
// 2.创建请求对象
NSURLRequest *request = [NSURLRequest requestWithURL:url];
// 3.创建 session 对象
NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[NSOperationQueue mainQueue]];
// 普通任务
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse * response, NSError *error) {
if (error) {
NSLog(@"NSURLSessionDataTaskerror:%@",error);
return;
}
// 解析数据
NSDictionary *dic = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:nil];
NSLog(@"NSURLSessionDataTaskdic:%@",dic);
//5.解析数据
NSLog(@"NSURLSessionDataTask:%@",[[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding]);
}];
// 执行 task
[dataTask resume];
}
执行结果
上传任务时,NSURLSession设置 POST 请求的请求体
- (void)sessionDataTaskPost {
// 1.请求路径
NSURL *url = [NSURL URLWithString:@"http://rap2api.taobao.org/app/mock/163155/fankui"];
// 2.创建请求对象
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
// 设置 post 请求方式
request.HTTPMethod = @"POST";
// 设置请求体
request.HTTPBody = [@"" dataUsingEncoding:NSUTF8StringEncoding];
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *session = [NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:queue];
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (error) {
NSLog(@"NSURLSessionDataTaskerror:%@",error);
return;
}
//5.解析数据
NSLog(@"NSURLSessionDataTask:%@",[[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding]);
}];
[dataTask resume];
}
执行结果
三 下载任务方式
NSURLConnection
下载文件时,先将整个文件下载到内存,然后再写入沙盒,如果文件比较大,就会出现内存暴涨的情况。
而使用NSURLSessionDownloadTask
下载文件,会默认下载到沙盒中的tem文件夹中,不会出现内存暴涨的情况,但在下载完成后会将tem中的临时文件删除,需要在初始化任务方法时,在completionHandler回调中增加保存文件的代码。 以下代码是实例化网络下载任务时将下载的文件保存到沙盒的caches文件夹中:
NSURLConnection下载文件
-
NSURLConnection
实例代码
- (void)downloadFile {
// 1.创建下载路径
NSURL *url = [NSURL URLWithString:@"http://dldir1.qq.com/qqfile/QQforMac/QQ_V5.4.0.dmg"];
// 2.创建请求对象
NSURLRequest *request = [NSURLRequest requestWithURL:url];
// NSURLConnection发送异步Get请求,并实现相应的代理方法,该方法iOS9.0之后废除了。
[NSURLConnection connectionWithRequest:request delegate:self];
}
#pragma mark - NSURLConnectionDataDelegate
// 接收到响应的时候:创建一个空的沙盒文件
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
NSLog(@"totalLength = %lld",response.expectedContentLength);
}
// 接收到具体数据:把数据写入沙盒文件中
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
NSLog(@"data length = %lu",(unsigned long)data.length);
}
// 下载完文件之后调用:关闭文件、清空长度
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
NSLog(@"下载完成");
}
打印结果
NSURLSessionDownloadTask下载文件
-
NSURLSessionDownloadTask
实例代码
- (void)sessionDownloadTask {
// 1.请求路径
NSURL *url = [NSURL URLWithString:@"http://www.pptbz.com/pptpic/UploadFiles_6909/201203/2012031220134655.jpg"];
// 2.创建 session 对象
NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[NSOperationQueue mainQueue]];
// 下载 task
NSURLSessionDownloadTask *task = [session downloadTaskWithURL:url completionHandler:^(NSURL *location, NSURLResponse *response, NSError *error) {
// 获取沙盒的 caches 路径
NSString *path = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"img.jpg"];
// 生成 url 路径
NSURL *url = [NSURL fileURLWithPath:path];
// 将文件保存到指定文件目录下
[[NSFileManager defaultManager] moveItemAtURL:location toURL:url error:nil];
}];
[task resume];
}
执行结果 - 断点调试
- 未保存图片之前,下载的资源在临时文件路径下
- 将下载资源从临时路径移动到指定路径下
四 请求方法的控制
NSURLConnection
实例化对象,实例化开始,默认请求就发送(同步发送
),不需要调用start
方法。而cancel
可以停止请求的发送,停止后不能继续访问,需要创建新的请求。NSURLSession
有三个控制方法,取消(cancel),暂停(suspend),继续(resume),暂停后可以通过继续恢复当前的请求任务。默认不发送请求,需要手动调用resume
方法
- (void)cancel;
- (void)suspend;
- (void)resume;
五 断点续传的方式
5.1 NSURLConnection
NSURLConnection
进行断点下载,通过设置访问请求的HTTPHeaderField
的Range
属性,开启运行循环,NSURLConnection的代理方法作为运行循环的事件源,接收到下载数据时代理方法就会持续调用,并使用NSOutputStream管道流
进行数据保存。
- 实例代码
// 开始下载
- (void)tapDownload {
if (self.conn) { // 如果有正在进行中的,需要停止先
[self tapCancel];
}
// 1.URL
NSURL *url = [NSURL URLWithString:@"http://dldir1.qq.com/qqfile/QQforMac/QQ_V5.4.0.dmg"];
// 2.请求
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
// 设置请求头
NSString *range = [NSString stringWithFormat:@"bytes=%lld-", self.currentLength];
[request setValue:range forHTTPHeaderField:@"Range"];
// 3.下载(创建完conn对象后,会自动发起一个异步请求)
self.conn = [NSURLConnection connectionWithRequest:request delegate:self];
}
5.2 NSURLSession
NSURLSession进行断点下载,当暂停下载任务后,如果 downloadTask (下载任务)为非空,调用 cancelByProducingResumeData:(void (^)(NSData *resumeData))completionHandler
这个方法,这个方法接收一个参数,完成处理代码块,这个代码块有一个 NSData 参数 resumeData,如果 resumeData 非空,我们就保存这个对象到视图控制器的 resumeData 属性中。在点击再次下载时,通过调用 [[self.session downloadTaskWithResumeData:self.resumeData] resume]
方法进行继续下载操作。 经过以上比较可以发现,使用NSURLSession进行断点下载更加便捷。
实例代码如下
- 一些属性
/** downloadtask*/
@property(nonatomic,strong)NSURLSessionDownloadTask *downloadTask;
/** data*/
@property(nonatomic,strong)NSData *resumeData;
/** session*/
@property(nonatomic,strong)NSURLSession *session;
- 开始下载和停止下载点击操作
#pragma mark - 断点续传
// 开始下载
- (void)tapDownload {
// 1.URL
NSURL *url = [NSURL URLWithString:@"http://dldir1.qq.com/qqfile/QQforMac/QQ_V5.4.0.dmg"];
if (self.resumeData) { // 之前已经下载过了
self.downloadTask = [self.session downloadTaskWithResumeData:self.resumeData];
} else {
self.session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[NSOperationQueue mainQueue]];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
self.downloadTask = [self.session downloadTaskWithRequest:request];
}
[self.downloadTask resume];
}
// 取消下载
- (void)tapSuspend {
if (self.downloadTask) {
[self.downloadTask suspend];
__weak typeof (self)weakSelf = self;
[self.downloadTask cancelByProducingResumeData:^(NSData *resumeData) {
NSLog(@"resumeData:%@",resumeData);
weakSelf.resumeData = resumeData;
weakSelf.downloadTask = nil;
}];
}
}
-
NSURLSessionDownloadDelegate
回调中保存数据
#pragma mark - NSURLSessionDownloadDelegate
/**
* 写入临时文件时调用
* @param bytesWritten 本次写入大小
* @param totalBytesWritten 已写入文件大小
* @param totalBytesExpectedToWrite 请求的总文件的大小
*/
- (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;
dispatch_async(dispatch_get_main_queue(), ^{
self.progressLbe.text = [NSString stringWithFormat:@"%.2f",progress];
});
}
// 下载完成调用
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location {
// location 还是一个临时路径,需要自己挪到需要的路径(caches 文件夹)
NSString *filePath = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:downloadTask.response.suggestedFilename];
[[NSFileManager defaultManager] moveItemAtURL:location toURL:[NSURL fileURLWithPath:filePath] error:nil];
NSLog(@"downloadTask 移动文件路径");
}
六 配置信息
NSURLSession
的构造方法sessionWithConfiguration:delegate:delegateQueue
中有一个NSURLSessionConfiguration
类的参数可以设置配置信息,其决定了cookie,安全和高速缓存策略,最大主机连接数,资源管理,网络超时
等配置。NSURLConnection
不能进行这个配置,相比于 NSURLConnection 依赖于一个全局的配置对象,缺乏灵活性而言。看看
NSURLSessionConfiguration
的三种配置方式
@property (class, readonly, strong) NSURLSessionConfiguration *defaultSessionConfiguration;
@property (class, readonly, strong) NSURLSessionConfiguration *ephemeralSessionConfiguration;
+ (NSURLSessionConfiguration *)backgroundSessionConfiguration:(NSString *)identifier;
-
defaultSessionConfiguration
:配置信息使用基于硬盘的持久话Cache,保存用户的证书到钥匙串,使用共享cookie存储; -
ephemeralSessionConfiguration
:配置信息和default大致相同。除了,不会把cache,证书,或者任何和Session相关的数据存储到硬盘,而是存储在内存中,生命周期和Session一致。比如浏览器无痕浏览等功能就可以基于这个来做; -
backgroundSessionConfigurationWithIdentifier:
:配置信息可以创建一个可以在后台甚至APP已经关闭的时候仍然在传输数据的session。
注意,后台Session一定要在创建的时候赋予一个唯一的identifier,这样在APP下次运行的时候,能够根据identifier来进行相关的区分。如果用户关闭了APP,IOS 系统会关闭所有的background Session。而且,被用户强制关闭了以后,IOS系统不会主动唤醒APP,只有用户下次启动了APP,数据传输才会继续。
本文参考
NSURLSession与NSURLConnection区别
更多相关文章参考
iOS-NSURLSession详解(附实战代码)
iOS-NSURLConnection使用详解