iOS网络--NSURLSession基本使用(1)

一、NSURLSession

NSURLSession是苹果对网络会话的封装,可以完全替代原来的NSURLConnection。相比于NSURLConnection,NSURLSession具备以下优势:

  1. 支持http2.0协议
  2. 在处理下载任务的时候可以将下载内容写入磁盘(NSURLSessionDownloadTask)
  3. 支持后台下载/上传
  4. 同一个NSURLSession可以发送多个请求,只需要建立一次连接
  5. 提供了全局的session(单例)与一些内置的配置,使用方便
  6. 下载的处理策略是多线程异步下载,效率高。

二、NSURLSessionTask

NSURLSession只是提供了一个会话,真正的下载任务是由NSURLSessionTask进行管理的。

                                 iOS网络--NSURLSession基本使用(1)_第1张图片

上面的图是NSURLSessionTask的类结构图,我们常用的就是NSURLSessionTask的两个直接子类:NSURLSessionDataTask和NSURLSessionDownloadTask。前者下载,上传任务都可以胜任,后者主要是对下载任务的管理,就是说后者中有对下载任务的细化管理,比如下载进度等。NSURLSessionDataTask还有一个直接子类--NSURLSessionUploadTask,这个类又将上传任务做了一个细化。个人认为这个类应该和NSURLSessionDownloadTask是同一层次的。

三、NSURLSession的使用

1.下载

使用NSURLSession下载资源有两种方式,一种是通过URL下载,一种是通过请求来下载。

     (1)、通过URL下载资源

通过URL来下载资源,对于下载数据回调的方式又有两种方式,一种是block的方式,另一种就是代理的方式

               1.通过block方式回调下载数据

//1.准备URL
    NSURL * url = [NSURL URLWithString:@"http://pic32.nipic.com/20130823/13339320_183302468194_2.jpg"];
//2.创建一个session 会话
NSURLSession * session = [NSURLSession sharedSession];
//3.通过session实例创建一个基于URL的任务
NSURLSessionDataTask * task = [session dataTaskWithURL:url completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
       NSLog(@"%@",[UIImage imageWithData:data]);
}];
//4.启动下载任务
[task resume];

特别注意最后需要手动启动下载任务。PS:这种block的回调方式没有进度。

                2.通过代理的方式来回调下载数据

//1.准备URL
    NSURL * url = [NSURL URLWithString:@"http://pic32.nipic.com/20130823/13339320_183302468194_2.jpg"];
//2.创建会话
NSURLSessionConfiguration * config = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession * session = [NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:[NSOperationQueue mainQueue]];
//3.创建下载任务
NSURLSessionDataTask * task  = [session dataTaskWithURL:url];
//4.启动下载任务
[task resume];

由于需要通过代理来回调下载数据,所以我们需要对session进行配置,NSURLSessionConfigration就是用来配置session的(嗯,英文好一点的小伙伴都看出来了?),我们使用它的类方法来创建一个配置,这个配置是默认的session配置(一般都用这个配置),然后通过这个配置来创建一个session,这里我们看到了代理--->参数delegate,这意味着我们需要在这个类中实现它的代理方法,这个等一会儿在说,后面的参数:delegateQueue表示代理在哪个队列中工作,这和session本身工作所在的线程不一样,详见这一篇博客:https://www.cnblogs.com/xiaowuqing/p/7512413.html

设置了delegate就需要服从相关的代理和实现代理的方法来实现回调数据给我们。由于这里我们创建的是NSURLSessionDataTask,所以我们服从的代理是NSURLSessionDataDelegate。这个代理下我们需要实现的方法是(常用的几个方法):

-(void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler{
    //接收相应的数据
    //和URLConnection的不同点在于接收到响应信息之后是否需要继续下载,必须自己配置
    //告诉服务器继续传递数据
    completionHandler(NSURLSessionResponseAllow);
    
}
-(void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data{
    //这里接收到真正的数据
}
-(void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error{
    //这里的error如果为空,则说明数据接收完毕
}

第一个方法就是收到服务器的相应头时回调的方法,我们一般在这个方法中计算所请求数据的总大小。需要特别注意的是这个方法也会回调一个block:completionHandler() 通过给这个block回调一个枚举值来告诉服务器还需不需要继续传递数据。

第二个方法就是回调的数据真正来的方法。

第三个方法就是回调数据结束了。

(3)、通过request来下载资源

        1.通过block的方式

//1.初始化URL
NSURL * url = [NSURL URLWithString:@"http://pic32.nipic.com/20130823/13339320_183302468194_2.jpg"];
//2.准备请求
NSURLRequest * request = [NSURLRequest requestWithURL:url];
//3.准备session
NSURLSession * session = [NSURLSession sharedSession];
//4.创建下载任务
NSURLSessionDataTask * task = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
    NSLog(@"%@",[UIImage imageWithData:data]);
}];
//5.启动下载任务
[task resume];

这里我们创建的request是默认的request,也就是get请求。与上面通过url来下载数据的不同之处在于,多了一步创建request的过程。

         2.通过delegate的方式

//1.初始化URL
NSURL * url = [NSURL URLWithString:@"http://pic32.nipic.com/20130823/13339320_183302468194_2.jpg"];
//2.准备请求
NSURLRequest * request = [NSURLRequest requestWithURL:url];
//3.创建session
NSURLSessionConfiguration * config = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession * session = [NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:[NSOperationQueue mainQueue]];
//4.创建下载任务
NSURLSessionDataTask * task = [session dataTaskWithRequest:request];
//5.开始下载
[task resume];

然后服从代理,实现代理的方法

-(void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler{
    //接收相应的数据
    //和URLConnection的不同点在于接收到响应信息之后是否需要继续下载,必须自己配置
    //告诉服务器继续传递数据
    completionHandler(NSURLSessionResponseAllow);
}
-(void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data{
    
}
-(void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error{
    NSLog(@"%@",[UIImage imageWithData:self.mData]);
}

2、使用NSURLSessionDownLoadTask下载

上面的下载方式是直接将数据下载到内存中,这样对于小型的数据来说内存是可以接受的,但是对于视频或者大一点的图片将其直接下载到内存确实欠妥。所以当我们需要下载文件时,最好使用NSURLDownloadTask来处理,这个类还能够将下载的数据写入磁盘中。

//这里的self.task是NSURLSessionDownLoadTask
NSURL * url = [NSURL URLWithString:@"http://pic15.nipic.com/20110628/1369025_192645024000_2.jpg"];
NSURLSessionConfiguration * config = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession * session = [NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:[NSOperationQueue mainQueue]];
self.task = [session downloadTaskWithURL:url];
[_task resume];

这里我们使用的是代理回调数据的方式,注意创建task用的是 downloadTaskWithURL 的方式,这个方法返回一个NSURLSessionDownLoadTask的对象。

遵守的协议:NSURLSessionDownloadDelegate

实现的代理方法:

-(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location{
    //将默认下载的数据从location中拷贝或者移动到自己的路径下面
    //当这个方法执行完毕这个临时文件就会被立刻销毁
    //所以要拷贝
    //获取保存的文件的路径
    NSString * path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).lastObject stringByAppendingPathComponent:@"1.jpg"];
    //将location对应的文件拷贝到指定的路径中
    [[NSFileManager defaultManager]moveItemAtURL:location toURL:[NSURL fileURLWithPath:path] error:nil];
}
//获取每次下载的进度
-(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite{
    //注意这里是浮点的要乘以1.0
    CGFloat pregress = totalBytesWritten*1.0/totalBytesExpectedToWrite;
   
}
//下载完毕
-(void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error{
    NSLog(@"%@",error.userInfo);
}

第一个方法是当将下载内容写到对应的一个locationURL下面时调用的方法,这个方法中我们需要将这个下载到location的内容移动到自己的目录下,因为这个方法一跑完就会将下载到location的内容删除。

第二个方法可以获取下载过程中的进度

bytesWritten:表示此次下载的字节数

totalBytesWritten:表示加上此次目前一共下载的字节数

totalBytesExpectedToWrite:表示一共需要下载多少字节。

所以进度就可以算出来啦~

最后一个方法就不用赘述了吧?

 

 

PS:对于上传任务,由于上传采用的方式一般是POST,而将数据写入到POST的请求体中是一件比较复杂而又细致的工作,所以我们一般都是使用的AFNetWorking这个框架~

你可能感兴趣的:(ios学习)