NSURLSession的简单使用
简介
我们都知道在iOS9.0之后,以前使用的NSURLConnection
已经过期,苹果推荐我们使用NSURLSession
来替换NSURLConnection
完成网路请求的相关操作。如果想查看关于NSURLConnection
的相关知识可以查看我的上一篇文章
NSURLSession
的使用一般分成两部操作:
- 通过
NSURLSession的实例
创建task; 执行task;
任务类型
NSURLSessionTask
是一个抽象子类,它有三个具体的子类是可以直接使用的NSURLSessionDataTask
、NSURLSessionDownloadTask
、NSURLSessionUploadTask
-
NSURLSessionDataTask:
使用NSData
对象发送和接收数据,通常用来负责App和服务器之间的交互请求。数据任务可以分片段一点一点从服务器返回数据也可以通过完成回调一次性返回全部数据。 -
NSURLSessionDownloadTask:
从文件中获取数据,并且支持在APP不运行时,后台下载。 -
NSURLSessionUploadTask:
将文件中数据上传,并且支持Appl不运行时,后台上传。
会话类型
NSURLSession
对象提供三种类型的会话,这三种类型的会话是由NSURLSessionConfiguration
配置对象决定的。
-
默认会话
+ (NSURLSessionConfiguration *)defaultSessionConfiguration;
它跟Foundation框架下的其他下载方法类似,默认的配置会将缓存存储在磁盘上。 -
短暂会话
+ (NSURLSessionConfiguration *)ephemeralSessionConfiguration;
它不保存数据到磁盘中,所有的缓存,认证资质,以及其他的信息都保留在关联该会话的内存中,因此,当会话结束时,这些数据都将自动丢失。 -
后台会话
<pre> + (NSURLSessionConfiguration *)backgroundSessionConfigurationWithIdentifier:(NSString *)identifier</pre>
允许程序在后台进行上传下载工作.
NSURLSessionDataTask
如果发起的请求比较简单,不需要监控返回数据的进度,我们可以使用block的方式进行请求
默认的Get请求
//1.确定URL
NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/login?username=520it&pwd=520it&type=JSON"];
//2.创建请求对象
NSURLRequest *request =[NSURLRequest requestWithURL:url];
//3.创建会话对象
NSURLSession * session=[NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
//4.创建Task
/*
第一个参数:请求对象
第二个参数:completionHandler 当请求完成之后调用
data:响应体信息
response:响应头信息
error:错误信息当请求失败的时候 error有值
*/
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
//6.解析数据
NSLog(@"%@",[[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding]);
}];
//5.执行Task
[dataTask resume];
注意:
-
[NSURLSession sharedSession];
该方法获取的对象是全局的NSURLSession
对象,所有app共用一个全局Session对象
. -
NSURLSession:
对象默认是挂起状态,需要手动调用resume
开启。 - 如下图所示,通过
NSURLSession
对象创建DataTask
总共有四种方式,通过URL的方式比较简单,不用再创建Request
对象,因为dataTaskWithURL
内部会自动的将请求路径作为参数创建一个请求对象(GET)
,但是这种情况不可以用来执行断点续传,这点要注意,下面咱再讲。
Post请求
跟NSURLConnection
对象的Post
请求是一样的,操作NSMutableURLRequest
,具体如下:
//1.确定URL
NSURL *url = [NSURL URLWithString:@"http://xxxx.html"];
//2.创建请求对象
NSMutableURLRequest *request =[NSMutableURLRequest requestWithURL:url];
//2.1 设置请求方法为post
request.HTTPMethod = @"POST";
//2.2 设置请求体
request.HTTPBody = [@"username=123&pwd=123&type=JSON" dataUsingEncoding:NSUTF8StringEncoding];
NSURLSessionDataDelegate代理方法
通过上面的方式可以看出通过block
的方式去处理返回数据是较为方便的,但是有的时候,我们可能需要监听网络请求的过程(比如下载文件的时候需要监听文件下载进度),此时block就满足不了我们的需求了,这个时候我们可以使用NSURLSession
的代理方法。
//1.url
NSURL *url = [NSURL URLWithString:@"http://xxx.html"];
//2.创建请求对象
NSURLRequest *request = [NSURLRequest requestWithURL:url];
//3.创建会话对象,设置代理
/*
第一个参数:配置信息 [NSURLSessionConfiguration defaultSessionConfiguration]
第二个参数:代理
第三个参数:设置代理方法在哪个线程中调用
[NSOperationQueue mainQueue] 主队列: 代理方法在主线程中调用
*/
NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[NSOperationQueue mainQueue]];
//4.创建Task
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request];
//5.执行Task
[dataTask resume];
代理方法
#pragma mark ----------------------
#pragma mark NSURLSessionDataDelegate
/**
* 1.接收到服务器的响应 它默认会取消该请求,只有允许处理服务器的响应,才会继续接收服务器返回的数据
*
* @param session 会话对象
* @param dataTask 请求任务
* @param response 响应头信息
* @param completionHandler 需要我们回调告诉系统
*/
-(void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler
{
NSLog(@"%s",__func__);
/*
NSURLSessionResponseCancel = 0,取消 默认
NSURLSessionResponseAllow = 1, 允许接收
NSURLSessionResponseBecomeDownload = 2, 变成下载任务
NSURLSessionResponseBecomeStream 变成流
*/
completionHandler(NSURLSessionResponseAllow);
}
/**
* 接收到服务器返回的数据 调用多次
* @param data 本次下载的数据
*/
-(void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data
{
NSLog(@"%s",__func__);
//拼接数据
[self.fileData appendData:data];
}
/**
* 请求结束或者是失败的时候调用
* @param error 错误信息
*/
-(void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
{
NSLog(@"%s",__func__);
//解析数据
NSLog(@"%@",[[NSString alloc]initWithData:self.fileData encoding:NSUTF8StringEncoding]);
}
注意:NSURLSession
对象在接收到响应的时候要先对响应做允许处理completionHandler(NSURLSessionResponseAllow);
只有这样它才会继续接收服务器返回的数据,执行后面的代理方法。
NSURLSessionDownloadTask
同样,我们先来看看Block的执行方式
NSURL *url = [NSURL URLWithString:@"http://xxx.html"];
//2.创建请求对象
NSURLRequest *request = [NSURLRequest requestWithURL:url];
//3.创建session
NSURLSession *session = [NSURLSession sharedSession];
//4.创建Task,该方法内部已经实现了边接收数据边写沙盒(tmp)的操作
NSURLSessionDownloadTask *downloadTask = [session downloadTaskWithRequest:request completionHandler:^(NSURL * _Nullable location, NSURLResponse * _Nullable response, NSError * _Nullable error) {
//6.1 拼接文件全路径
NSString *fullPath = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:response.suggestedFilename];
//6.2 剪切文件,将下载下来的文件剪切到Cache目录下。因为location是NSURL类型;
[[NSFileManager defaultManager]moveItemAtURL:location toURL:[NSURL fileURLWithPath:fullPath] error:nil];
NSLog(@"%@",fullPath);
}];
//5.执行Task
[downloadTask resume];
Block的执行方式可以边接收数据边写沙盒(tmp),不需要担心内存飙升的问题,但是同样我们无法监听文件下载进度,所以我们来一遍代理方式
代理方式
- (IBAction)startBtnClick:(id)sender
{
NSURL *url = [NSURL URLWithString:@"http://xxx.html"];
//2.创建请求对象
NSURLRequest *request = [NSURLRequest requestWithURL:url];
//3.创建session
NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
self.session = [NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:[NSOperationQueue mainQueue]];
//4.创建Task
NSURLSessionDownloadTask *downloadTask = [self.session downloadTaskWithRequest:request];
//5.执行Task
[downloadTask resume];
self.downloadTask = downloadTask;
}
请求的几种状态
//暂停是可以恢复下载的
- (IBAction)suspendBtnClick:(id)sender
{
NSLog(@"+++++++++++++++++++暂停");
[self.downloadTask suspend];
}
//cancel:不能恢复下载
//cancelByProducingResumeData:可以恢复下载,需要借助于resumeData
- (IBAction)cancelBtnClick:(id)sender
{
NSLog(@"+++++++++++++++++++取消");
//[self.downloadTask cancel];
//恢复下载的数据!=文件数据
[self.downloadTask cancelByProducingResumeData:^(NSData * _Nullable resumeData) {
self.resumData = resumeData;
}];
}
//先判断本地是否已经有缓存,如果有则继续上次暂停的下载;
- (IBAction)goOnBtnClick:(id)sender
{
NSLog(@"+++++++++++++++++++恢复下载");
if(self.resumData)
{
self.downloadTask = [self.session downloadTaskWithResumeData:self.resumData];
}
[self.downloadTask resume];
}
代理方法:
#pragma mark ----------------------
#pragma mark NSURLSessionDownloadDelegate
/**
* 写数据
*
* @param session 会话对象
* @param downloadTask 下载任务
* @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
{
//1. 获得文件的下载进度
NSLog(@"%f",1.0 * totalBytesWritten/totalBytesExpectedToWrite);
}
/**
* 当恢复下载的时候调用该方法
*
* @param fileOffset 从什么地方下载
* @param expectedTotalBytes 文件的总大小
*/
-(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didResumeAtOffset:(int64_t)fileOffset expectedTotalBytes:(int64_t)expectedTotalBytes
{
NSLog(@"%s",__func__);
}
/**
* 当下载完成的时候调用
*
* @param location 文件的临时存储路径
*/
-(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location
{
NSLog(@"%@",location);
//1 拼接文件全路径
NSString *fullPath = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:downloadTask.response.suggestedFilename];
//2 剪切文件
[[NSFileManager defaultManager]moveItemAtURL:location toURL:[NSURL fileURLWithPath:fullPath] error:nil];
}
/** * 请求结束 */
-(void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
{
NSLog(@"didCompleteWithError");
}
通过上面的代码我们知道NSRULSessionDownLoadTask
的几种状态
- (void)suspend;//暂停下载
- (void)resume; //继续下载
- (void)cancel; //取消下载
suspend
可以让当前的任务暂停
resume
方法不仅可以启动任务,还可以唤醒suspend
状态的任务
cancel
方法可以取消当前的任务,你也可以向处于suspend
状态的任务发送cancel
消息,任务如果被取消便不能再恢复到之前的状态.
总结:利用NSRULSessionDownLoadTask
对象下载数据的过程中,如果用户在下载过程中未保存恢复下载的数据即退出程序,则不能恢复下载,所以我们可以利用NSURLSessionDataTask
对象进行下载,过程其实类似于NSURLConnection
,参考上一篇文章