iOS Developer

NSURLSession的简单使用

2016-12-01  本文已影响83人  Mark_Guan

简介

我们都知道在iOS9.0之后,以前使用的NSURLConnection已经过期,苹果推荐我们使用NSURLSession来替换NSURLConnection完成网路请求的相关操作。如果想查看关于NSURLConnection的相关知识可以查看我的上一篇文章

NSURLSession的使用一般分成两部操作:

  1. 通过 NSURLSession的实例创建task;
  2. 执行task;

任务类型

NSURLSessionTask是一个抽象子类,它有三个具体的子类是可以直接使用的NSURLSessionDataTaskNSURLSessionDownloadTaskNSURLSessionUploadTask

  1. NSURLSessionDataTask:使用NSData对象发送和接收数据,通常用来负责App和服务器之间的交互请求。数据任务可以分片段一点一点从服务器返回数据也可以通过完成回调一次性返回全部数据。

  2. NSURLSessionDownloadTask:从文件中获取数据,并且支持在APP不运行时,后台下载。

  3. NSURLSessionUploadTask:将文件中数据上传,并且支持Appl不运行时,后台上传。

会话类型

NSURLSession对象提供三种类型的会话,这三种类型的会话是由NSURLSessionConfiguration配置对象决定的。

  1. 默认会话 + (NSURLSessionConfiguration *)defaultSessionConfiguration; 它跟Foundation框架下的其他下载方法类似,默认的配置会将缓存存储在磁盘上。

  2. 短暂会话 + (NSURLSessionConfiguration *)ephemeralSessionConfiguration; 它不保存数据到磁盘中,所有的缓存,认证资质,以及其他的信息都保留在关联该会话的内存中,因此,当会话结束时,这些数据都将自动丢失。

  3. 后台会话
    <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];

注意:

  1. [NSURLSession sharedSession];该方法获取的对象是全局的NSURLSession对象,所有app共用一个全局Session对象.
  2. NSURLSession:对象默认是挂起状态,需要手动调用resume开启。
  3. 如下图所示,通过NSURLSession对象创建DataTask总共有四种方式,通过URL的方式比较简单,不用再创建Request对象,因为dataTaskWithURL内部会自动的将请求路径作为参数创建一个请求对象(GET),但是这种情况不可以用来执行断点续传,这点要注意,下面咱再讲。
创建DataTask的几种方式

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,参考上一篇文章

上一篇下一篇

猜你喜欢

热点阅读