USURLSession基本使用介绍

2016-05-01  本文已影响1274人  凌巅

USURLSession基本使用介绍

在2013的WWDC上,苹果推出了NSURLConnection的继任者NSURLSession,并且在iOS9.0之后,以前使用的NSURLConnection将提示过期,推荐使用NSURLSession来替换NSURLConnection完成网路请求相关操作。与 NSURLConnection 一样,NSURLSession 指的也不仅是同名类 NSURLSession,还包括一系列相互关联的类。NSURLSession 包括了与之前相同的组件,NSURLRequest 与 NSURLCache,但是把 NSURLConnection 替换成了 NSURLSession、NSURLSessionConfiguration 以及 NSURLSessionTask 的 3 个子类:NSURLSessionDataTask,NSURLSessionUploadTask,NSURLSessionDownloadTask,这三个子类可以直接使用,每个任务都可以挂起(suspend),结束(cancel) 和 执行(resume),调用响应的函数即可
</br>
与 NSURLConnection 相比,NSURLsession 最直接的改进就是可以配置每个 session 的缓存,协议,cookie,以及证书策略(credential policy),甚至跨程序共享这些信息。这将允许程序和网络基础框架之间相互独立,不会发生干扰。每个 NSURLSession 对象都由一个 NSURLSessionConfiguration 对象来进行初始化,后者指定了刚才提到的那些策略以及一些用来增强移动设备上性能的新选项。


1、NSURLSessionDataTask 获取服务器上的数据,返回相关数据,获取后直接处理
2、NSURLSessionUploadTask 创建一个上传任务,在上传时需要制定文件源或数据源,一般来说,对于一个上传任务,也会收到服务的响应也会有相关数据返回,所以NSURLSessionUploadTask继承于NSURLSessionDataTask
3、NSURLSessionDownloadTask 下载服务器上的数据,当任务结束的时候,他会带回一个下载文件的一个临时文件路径,所以在下载大容量任务时,使用尤为方便。
每一个task都是可以取消,暂停或者恢复的。当一个 download task 取消时,可以通过选项来创建一个恢复数据(resume data),然后可以传递给下一次新创建的 download task,以便继续之前的下载,这在断点下载的时候尤为有用。

NSURLSession常用的类

1、NSURL:根据url生成的请求地址
2、NSURLRequest:封装的一个请求,携带发送给服务器的全部数据,里面包含一个NSURL对象,请求方法,请求头,请求体等等。
3、NSMutableURLRequest:这个是NSURLRequest的子类,通过名字我们可以看出这是一个可变的对象,我们可以在这里自定义设置发送的服务器的全部数据(超市等待时间、请求方法、请求体、请求头)
4、NSURLResponse:服务的响应类,和NSURLRequest对象,包含服务返回的响应头部数据
5、NSURLSessionConfiguration 用于配置会话的属性,可以通过该类配置会话的工作模式:
+ (NSURLSessionConfiguration *)defaultSessionConfiguration; 工作模式类似于原来的NSURLConnection,可以使用缓存的Cache,Cookie,鉴权
+ (NSURLSessionConfiguration *)ephemeralSessionConfiguration; 不使用缓存的Cache,Cookie,鉴权。
+ (NSURLSessionConfiguration *)backgroundSessionConfiguration:(NSString *)identifier; 创建一个后台 session,后台 session 不同于常规的,普通的 session,它甚至可以在应用程序挂起,退出或者崩溃的情况下运行上传和下载任务,创建Configuration对象的时候需要给一个NSString的ID用于用于标记后台的session。(稍后详细描述)
6、NSURLSession:会话对象

NSURLSession的使用步骤

1、根据url创建一个NSURL对象
2、根据创建的NSURL创建一个NSURLRequest对象,创建请求对象(此对象内容全部都是默认值,如:请求方法默认是GET),如果想要自定数据则创建NSMutableURLRequest对象
3、创建会话对象NSURLSession,创建NSURLSession对象有三种方法:

1)+ (NSURLSession *)sharedSession; 返回一个默认的NSURLSession,使用共享的会话,该会话使用全局的Cache,Cookie和证书
2)+ (NSURLSession *)sessionWithConfiguration:(NSURLSessionConfiguration *)configuration; 返回一个根据刚才创建的Configuration的NSURLSession对象,系统默认创建一个新的OperationQueue处理Session的消息
3)+ (NSURLSession *)sessionWithConfiguration:(NSURLSessionConfiguration *)configuration delegate:(nullable id <NSURLSessionDelegate>)delegate delegateQueue:(nullable NSOperationQueue *)queue; 返回一个根据刚才创建的Configuration的NSURLSession对象,可以设定回调的delegate(注意这个回调delegate会被强引用),并且可以设定delegate在哪个OperationQueue回调,如果我们将其设置为[NSOperationQueue mainQueue]就能在主线程进行回调非常的方便

4、使用创建好的NSURLSession对象和NSURLRequest对象创建一个NSURLSessionTask任务,NSURLSessionDataTask、NSURLSessionUploadTask 或者 NSURLSessionDownloadTask
5、调用resume开始工作
6、当不再需要连接调用Session的invalidateAndCancel直接关闭,或者调用finishTasksAndInvalidate等待当前Task结束后关闭。这时Delegate会收到URLSession:didBecomeInvalidWithError:这个事件。Delegate收到这个事件之后会被解引用。
</br>
和NSURLConnection一样,NSURLSession也提供了两种形式的使用,代理模式和非代理模式

非代理模式

每个task的构造方法都提供了一个–dataTaskWithRequest:completionHandler:的函数,类似NSURLConnection的sendAsynchronousRequest:queue:completionHandler:sendSynchronousRequest:returningResponse:error:模式,只是NSURLSession仅有异步版本。
例如,如果创建一个NSURLSessionDataTask任务:

    NSURLSessionConfiguration *sessionConfig = [NSURLSessionConfiguration defaultSessionConfiguration];
    self.session = [NSURLSession sessionWithConfiguration:sessionConfig delegate:self delegateQueue:[NSOperationQueue mainQueue]];
    NSString *imageURl = @"http://7xt5rm.com2.z0.glb.clouddn.com/picjumbo.com_download.jpg";
    NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:imageURl]];
    
    NSURLSessionDataTask *task = [self.session dataTaskWithRequest:request
                                         completionHandler:
     ^(NSData *data, NSURLResponse *response, NSError *error) {
         //接受的数据data、服务器响应response、错误代码error
     }];

    //启动task
    [task resume];
    //其它方法,如取消任务,暂停任务等
    //[task cancel];
    //[task suspend]

再者创建一个NSURLSessionUploadTask任务

    NSURLSessionConfiguration *sessionConfig = [NSURLSessionConfiguration defaultSessionConfiguration];
    self.session = [NSURLSession sessionWithConfiguration:sessionConfig delegate:self delegateQueue:[NSOperationQueue mainQueue]];
    NSString *imageURl = @"http://7xt5rm.com2.z0.glb.clouddn.com/picjumbo.com_download.jpg";
    NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:imageURl]];
    NSData *data = ...; //上传任务需要一个需要上传的NSData对象或者一个本地文件路径对应的NSURL
    
    NSURLSessionDataTask *uploadTask = [self.session uploadTaskWithRequest:request
                                                            fromData:data
                                                   completionHandler:
     ^(NSData *data, NSURLResponse *response, NSError *error) {
         //接受的数据data、服务器响应response、错误代码error
     }];
     
    //启动task
    [uploadTask resume];
    //其它方法,如取消任务,暂停任务等
    //[uploadTask cancel];
    //[uploadTask suspend];

我们再来看看NSURLSessionDownloadTask任务,下载任务的不同之处在于,NSURLSessionDownloadTask会一点一点的将下载数据写入本地的临时文件,回调block会带回一个下载完成的临时文件的地址,我们需要把文件从这个临时地址移动到文件沙盒中保存起来使用。

    NSURLSessionConfiguration *sessionConfig = [NSURLSessionConfiguration defaultSessionConfiguration];
    self.session = [NSURLSession sessionWithConfiguration:sessionConfig delegate:self delegateQueue:[NSOperationQueue mainQueue]];
    NSString *imageURl = @"http://7xt5rm.com2.z0.glb.clouddn.com/picjumbo.com_download.jpg";
    NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:imageURl]];
    
    NSURLSessionDownloadTask *downloadTask = [self.session downloadTaskWithRequest:request
                                                         completionHandler:
    ^(NSURL *location, NSURLResponse *response, NSError *error) {
        //文件临时地址location,服务器响应response、错误代码error
        //将临时文件移动到app沙盒中
        NSString *documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
        NSURL *documentsDirectoryURL = [NSURL fileURLWithPath:documentsPath];
        NSURL *newFileLocation = [documentsDirectoryURL URLByAppendingPathComponent:[[response URL] lastPathComponent]];
        [[NSFileManager defaultManager] copyItemAtURL:location toURL:newFileLocation error:nil];
    }];

    //启动task
    [downloadTask resume];
    //其它方法,如取消任务,暂停任务等
    //[downloadTask cancel];
    //[downloadTask suspend];

代理模式

NSURLSession有几个代理协议NSURLSessionDelegateNSURLSessionTaskDelegateNSURLSessionDataDelegateNSURLSessionDownloadDelegate这几个协议个呈继承关系,NSURLSessionTaskDelegate继承NSURLSessionDelegate,NSURLSessionDataDelegate和NSURLSessionDownloadDelegate继承自NSURLSessionTaskDelegate,实现不同的任务,就实现相应的协议。在这里我们以NSURLSessionDownloadDelegate协议为例:

    NSURLSessionConfiguration *sessionConfig = [NSURLSessionConfiguration defaultSessionConfiguration];
    self.session = [NSURLSession sessionWithConfiguration:sessionConfig delegate:self delegateQueue:[NSOperationQueue mainQueue]];
    NSString *imageURl = @"http://7xt5rm.com2.z0.glb.clouddn.com/picjumbo.com_download.jpg";
    NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:imageURl]];
    
    //创建下载task
    NSURLSessionDownloadTask *downloadTask = [self.session downloadTaskWithRequest:request];
    
    //启动task
    [downloadTask resume];
    //其它方法,如取消任务,暂停任务等
    //[downloadTask cancel];
    //[downloadTask suspend];

代理方法,主要有这么几个:

//当接收到服务器响应的时候调用
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask
                                 didReceiveResponse:(NSURLResponse *)response
                                  completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler;

//下载完成之后调用该方法
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask
                              didFinishDownloadingToURL:(NSURL *)location;

//当接收到下载数据的时候调用,可以在该方法中监听文件下载的进度该方法会被调用多次
//totalBytesWritten:已经写入到文件中的数据大小
//totalBytesExpectedToWrite:目前文件的总大小
//bytesWritten:本次下载的文件数据大小
//可以在此函数中计算下载进度
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask
                                           didWriteData:(int64_t)bytesWritten
                                      totalBytesWritten:(int64_t)totalBytesWritten
                              totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite;
//恢复下载的时候调用该方法
//fileOffset:恢复之后,要从文件的什么地方开发下载
//expectedTotalBytes:该文件数据的总大小
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask
                                      didResumeAtOffset:(int64_t)fileOffset
                                     expectedTotalBytes:(int64_t)expectedTotalBytes;

//当请求完成之后调用该方法
//不论是请求成功还是请求失败都调用该方法,如果请求失败,那么error对象有值,否则那么error对象为空
//所有方法之中最后调用
-(void)URLSession:(nonnull NSURLSession *)session task:(nonnull NSURLSessionTask *)task didCompleteWithError:(nullable NSError *)error

和NSURLConnection一样我们这里也介绍一下断点下载的相关代码

第一种:每一个task都是有三种状态挂起、执行和取消,所以我们可以在暂停时刻挂起任务,重新下载时执行任务即可
        if (downloadTask.state == NSURLSessionTaskStateSuspended) {
            [downloadTask resume];
        } else {
            [downloadTask suspend];
        }
     但是很多时候不是使用这种方法,不知有哪里不妥。。
第二种:取消的任务的时候保存已下载文件的信息,在恢复下载时,传入此信息。
    //取消下载
    [downloadTask cancelByProducingResumeData:^(NSData * __nullable resumeData) {
        self.resumeData = resumeData;
    }];
    //恢复下载
    downloadTask = [self.session downloadTaskWithResumeData:self.resumeData];
    [downloadTask resume];
    比较常用的是这一种。。

后台下载

前面讲到我们可以通过设置NSURLSessionConfiguration的属性BackgroundSession来实现后台下载,在Task执行的时候,用户切到后台,Session会和ApplicationDelegate做交互。当程序切到后台后,在BackgroundSession中的Task还会继续下载。
在切到后台之后,Session的Delegate不会再收到Task相关的消息,直到所有Task全都完成后,系统会调用ApplicationDelegate的application:handleEventsForBackgroundURLSession:completionHandler:回调,之后“汇报”下载工作,对于每一个后台下载的Task调用Session的Delegate中的URLSession:downloadTask:didFinishDownloadingToURL:(成功的话)和URLSession:task:didCompleteWithError:(成功或者失败都会调用)之后调用Session的Delegate回调URLSessionDidFinishEventsForBackgroundURLSession:

看一下代码:
在AppDelegate.m中,加入后台处理函数

- (void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier completionHandler:(void (^)())completionHandler{
    
    self.backgroundTransferCompletionHandler = completionHandler;
    
}

实现delegate的-(void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session方法

// 后台传输完成,处理URLSession完成事件
-(void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session{
    AppDelegate *appDelegate = [UIApplication sharedApplication].delegate;
    
    //检查一下是否所有的下载任务都已经完成
    [self.session getTasksWithCompletionHandler:^(NSArray *dataTasks, NSArray *uploadTasks, NSArray *downloadTasks) {
        if ([uploadTasks count] == 0) {
            if (appDelegate.backgroundTransferCompletionHandler != nil) {
                //在ApplicationDelegate被唤醒后,会有个参数ComplietionHandler,这个参数是个Block,这个参数要在后面Session的Delegate中didFinish的时候调用一下
                
                void(^completionHandler)() = appDelegate.backgroundTransferCompletionHandler;
                appDelegate.backgroundTransferCompletionHandler = nil;
                completionHandler();
            }
        }    
        
    }];
    //执行其他操作
    NSLog(@"All tasks are finished"); 
}
上一篇下一篇

猜你喜欢

热点阅读