NSURLSession

2016-07-25  本文已影响136人  linatan

Using NSURLSession
NSURLSession API

会话类型

  1. default session:与其他下载URL的Foundation方法类似,使用基于磁盘的缓存策略,并在用户的keychain中存储证书
  2. Ephemeral session:不存储任何数据到磁盘中,所有缓存、证书存储都保存在RAM中并与会话绑定,应用结束会话时,这些都会被释放
  3. background session:类似于default session,除了有一个独立的进程进行来处理所有的数据传输。
  4. 还有个单例 shared session,没有configuration。

任务类型

  1. data tasks:使用NSData对象来发送和接收数据。数据任务可以分片返回数据,也可以通过完成处理器一次性返回数据。由于数据任务不存储数据到文件,所以不支持background session
  2. download tasks:以文件的形式接收数据,当程序不运行时支持后台下载
  3. upload tasks:通常以文件的形式发送数据,支持background session

后台传输

NSURLSession支持在应用挂起时在后台传输数据,后台传输只由使用background session配置的对象创建的会话进行调用,backgroundSessionConfigurationWithIdentifier:
使用后台会话时,由于其是在一个独立的进程中传输,且重启应用进程相当损耗资源,只有少量特性可以使用,所以有以下限制:

  1. 会话必须提供事件分发(event delivery)代理
  2. 只支持http和https协议
  3. 总是伴随重定向
  4. 只有从文件中upload tasks才可以,从data objects或者stream将会失败
  5. 如果当应用在后台时初始化的后台传输,则配置对象的discretionary属性为true

在iOS中,当我们的应用不再运行时,如果后台下载任务完成或者需要证书,则系统会在后台自动重启我们的应用,同时调用UIApplicationDelegate对象的application:handlerEventsForBackgroundURLSession:completionHandler:方法。这个调用会提供启动的应用的session的标识。我们的应用应当存储completion handler,使用相同的标识来创建后台配置对象,然后使用配置对象来创建会话。新的会话会与运行的后台activity关联。当会话完成后台下载任务时,会给会话代理发送一个URLSessioinDidFinishEventsForBackgroundURLSession:消息。代理对象然后在main thread调用存储的completion handler,这样操作系统才知道再次暂停你的应用是安全的。
如果在程序挂起时有任何任务完成,则会调用URLSession:downloadTask:didFinishDownloadingToURL:方法。
同样的,如果任务需要证书,则NSURLSession对象会在适当的时候调用URLSession:task:didReceiveChallenge:completionHandler: 和URLSession:didReceiveChallenge:completionHandler:方法。

会话和任务对象实现了NSCopying协议:

  1. 当应用拷贝一个会话或任务对象时,会获取相同对象的指针(未创建新对象)
  2. 当应用拷贝一个配置对象时,会获取一个可单独修改的新的对象(创建新对象)

NSURLSession的生命周期

Life Cycle of a URL Session
中文翻译

创建和配置NSURLSession

配置选项

  1. 支持对缓存、cookies、证书的私有存储 ,以及对单例会话特定的protocol
  2. 关联到一个特定请求(任务),或者一组请求(会话)的认证
  3. 可以通过url上传或者下载文件
  4. 配置主机的最大连接数
  5. 当资源无法在一个确定时间内下载时,配置一个超时时间
  6. 支持安全传输协议TLS的版本区间
  7. 自定义代理字典
  8. cookie的控制策略
  9. HTTP的传输控制

因为大部分的配置都在一个configuration对象中设置,可以重用一些基本设置;你可以在任何时间安全的修改一个configuration对象。因为当创建一个会话时,configuration对象的传递是由深拷贝实现的,所以修改只会影响之后新创建的会话,不会对已存在的会话造成影响。初始化一个会话对象(session object)可以进行如下操作:

  1. 一个configuration对象用来管理会话或任务的行为
  2. optional:一个代理对象用来表示接收数据的进度,会话任务或会话其他事件的进度,比如服务器认证,决定一个加载请求是否可转换为下载请求等等
  3. 如果没有指定一个代理,NSURLSession对象将使用系统默认提供的代理。在这种方式中,你可以轻松的使用NSURLSession方法替代已存在的sendAsynchronousRequest:queue:completionHandler:方法

app在后台传输数据,必须自定义代理

Demo——利用配置项创建NSURLSession

- (void)setUpSession
{
    NSURLSessionConfiguration *defaultConfiguration = [NSURLSessionConfiguration defaultSessionConfiguration];
    NSURLSessionConfiguration *ephemeralConfiguration = [NSURLSessionConfiguration ephemeralSessionConfiguration];
    NSURLSessionConfiguration *backgroundConfiguration = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:@"backgroundConfiguration"];
    
    //针对defaultConfiguration配置cache
    NSString *cacheDirectory =  NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES).firstObject;
    NSString *cachePath = [cacheDirectory stringByAppendingString:@"myCache"];
    
    NSURLCache *cacheUrl = [[NSURLCache alloc]initWithMemoryCapacity:16384 diskCapacity:268435456 diskPath:cachePath];
    defaultConfiguration.URLCache = cacheUrl;
    defaultConfiguration.requestCachePolicy = NSURLRequestUseProtocolCachePolicy;
    
    NSOperationQueue *operationQueue = [NSOperationQueue mainQueue];
    //创建session
    NSURLSession *defaultSession = [NSURLSession sessionWithConfiguration:defaultConfiguration delegate:self delegateQueue:operationQueue];
    //...
}

使用系统提供的代理获取资源

- (void)getDataWithSystemDefaultDelegate
{
    NSURLSessionConfiguration *defaultConfiguration = [NSURLSessionConfiguration defaultSessionConfiguration];
    
    NSURLSession *sessionWithoutADelegate = [NSURLSession sessionWithConfiguration:defaultConfiguration];
    NSURL *url = [NSURL URLWithString:@"https://www.example.com/"];
    
    [[sessionWithoutADelegate dataTaskWithURL:url completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
        NSLog(@"Got response %@ with error %@.\n", response, error);
        NSLog(@"DATA:\n%@\nEND DATA\n", [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
              }] resume];
}

使用自定义的代理获取资源

需要实现如下2个方法:
URLSession:dataTask:didReceiveData:
URLSession:task:didCompleteWithError:

下载文件

app需要实现以下的代理方法

  1. URLSession:downloadTask:didFinishDownloadingToURL:提供下载内容临时存储的目录地址。注意:在这个方法返回之前,必须打开文件来进行读取或者将下载内容移动到一个永久目录;当方法返回后,临时文件将会被删除。
  2. URLSession:downloadTask:didWriteData:totalBytesWritten:totalBytesExpectedToWrite:提供下载的进度信息
  3. URLSession:downloadTask:didResumeAtOffset:expectedTotalBytes:告诉app尝试恢复之前失败的下载
  4. URLSession:task:didCompleteWithError:告诉app下载失败
  1. 当下载任务安排在background session中时,当app停止运行时下载继续;
  2. 如果是安排在default/ephemeral session中时,当重新开启app时,下载会重新开始。
  3. 与服务器传输数据期间,如果用户进行了暂停操作,app可以调用cancelByProducingResumeData:方法取消任务。然后,app可以将已传输的数据作为参数传递给downloadTaskWithResumeData:或者downloadTaskWithResumeData:completionHandler:来创建一个新的下载任务继续下载。
    4)如果传输失败,代理会调用URLSession:task:didCompleteWithError:。如果任务可以再运行,userInfo中包含键NSURLSessionDownloadTaskResumeData,可以将数据作为参数传递给downloadTaskWithResumeData:或者downloadTaskWithResumeData:completionHandler:来创建一个新的下载任务进行重试

上传数据内容

app可以对Http post请求提供三种方式的请求体:NSData对象、文件、数据流

NSData上传

- (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)request 
                                         fromData:(NSData *)bodyData;
- (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)request 
                                         fromData:(NSData *)bodyData 
                                completionHandler:(void (^)(NSData *data, NSURLResponse *response, NSError *error))completionHandler;

file上传

- (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)request 
                                         fromFile:(NSURL *)fileURL;
- (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)request 
                                         fromFile:(NSURL *)fileURL 
                                completionHandler:(void (^)(NSData *data, NSURLResponse *response, NSError *error))completionHandler;

stream上传

- (NSURLSessionUploadTask *)uploadTaskWithStreamedRequest:(NSURLRequest *)request
- (void)URLSession:(NSURLSession *)session 
              task:(NSURLSessionTask *)task 
 needNewBodyStream:(void (^)(NSInputStream *bodyStream))completionHandler;

后台任务

使用NSURLSession,当下载完成时,app将会自动启动;代理中2个主要方法:

//负责创建session,存储completionHandler
- (void)application:(UIApplication *)application 
handleEventsForBackgroundURLSession:(NSString *)identifier 
  completionHandler:(void (^)(void))completionHandler;
- (void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session;
上一篇下一篇

猜你喜欢

热点阅读