NSURLSession

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;
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,080评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,422评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,630评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,554评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,662评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,856评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,014评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,752评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,212评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,541评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,687评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,347评论 4 331
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,973评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,777评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,006评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,406评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,576评论 2 349

推荐阅读更多精彩内容