NSURLSession之初探

前言

如果问一个iOS开发的同学,你们的网络请求是使用的什么框架呢?不用怀疑,十有八九都会回答使用的是AFNetworking。你也可能自做iOS开发以来,已经无数次的使用AFNetworking中的AFHTTPSessionManager对象或AFURLSessionManager对象发送GET/POST请求,但你真的知道这样一个看似简单的网络请求是怎么实现的吗?

AFNetworking核心---NSURLSession

  • NSURLSession对象是什么

NSURLSession is a replacement API for NSURLConnection. It provides options that affect the policy of, and various aspects of the mechanism by which NSURLRequest objects are retrieved from the network.

An NSURLSession may be bound to a delegate object. The delegate is invoked for certain events during the lifetime of a session, such as server authentication or determining whether a resource to be loaded should be converted into a download.

NSURLSession instances are threadsafe.The default NSURLSession uses a system provided delegate and is appropriate to use in place of existing code that uses +[NSURLConnection sendAsynchronousRequest:queue:completionHandler:]

An NSURLSession creates NSURLSessionTask objects which represent the action of a resource being loaded. These are analogous to NSURLConnection objects but provide for more control and a unified delegate model.

   从NSURLSession.h文件中对NSURLSession对象的描述,我们可以知道如下几条信息
 1 NSURLSession对象是NSURLConnection对象的替代api。在iOS7.0之前,不管当时你使用牛逼的ASIHttpRequest网络框架还是使用原生网络请求,都绕不过NSURLConnection。对,从这个时候NSURLSession成为了苹果的亲儿子。NSURLSession对象通过创建时设置配置选项NSURLSessionConfiguration对象,影响NSURLRequest对象的方方面面,如网络超时时间、缓存策略、是否允许使用蜂窝网络用于请求等。

2 当你查看了NSURLSession.h文件,你会发现其中声明了很多代理方法。你肯定会想这些代理方法什么时候会被触发、谁又是这些代理事件的委托者呢?一切都没错!就如An NSURLSession may be bound to a delegate object说的,NSURLSession对象与代理对象有着千丝万缕的联系,在通过NSURLSession对象参与网络请求的故事里,它就是代理事件的委托者。显而易见,所有代理事件的触发都将会在NSURLSession对象的生命周期中调用。

3 NSURLSession是线程安全的,默认的NSURLSession对象使用使用系统提供的代理对象( 当然你也可以为其指定代理对象),在合适的地方替代原有使用NSURLConnection发送网络请求的代码。如同NSURLConnection,我们也可以使用completionHandler回调获取数据,并不需要自己处理代理事件。

4 当你查看了NSURLSession.h文件,你会发现NSURLSessionTask及其子类都可通过NSURLSession提供的类方法创建的,你可以把NSURLSessionTask理解为一个表示某项资源将被加载的任务。

  • NSURLSession对象分类
    NSURLSession通过设置不同类别的NSURLSessionConfiguration对象可配置不同类别的NSURLSession对象
    + (NSURLSession *)sessionWithConfiguration: (NSURLSessionConfiguration *)configuration;
    + (NSURLSession *)sessionWithConfiguration: (NSURLSessionConfiguration *)configuration delegate:(nullable id <NSURLSessionDelegate>)delegate delegateQueue:(nullable NSOperationQueue *)queue;

    很明显,NSURLSessionConfiguration的类别决定了NSURLSession对象的性质。
    #if FOUNDATION_SWIFT_SDK_EPOCH_AT_LEAST(8)
    @property (class, readonly, strong) NSURLSessionConfiguration *defaultSessionConfiguration;
    @property (class, readonly, strong) NSURLSessionConfiguration *ephemeralSessionConfiguration;
    #endif
    + (NSURLSessionConfiguration *)backgroundSessionConfigurationWithIdentifier:(NSString *)identifier NS_AVAILABLE(10_10, 8_0);

sessions.png

如果现在你不能理解它们间的差异也没有关系!通过描述或许也能看明白它们间的差异是围绕着数据缓存(caches)、cookies、证书的存储方式不同展开,需要注意backgroundSession是一个后台Session,我们可以通过该类别的session在后台进行数据的下载与上传。

NSURLSession之代理事件

Delgates.png
//该协议中的方法处理session层级的事件,具体事件调用会在后续的例子中演示
@protocol NSURLSessionDelegate <NSObject>
@optional
- (void)URLSession:(NSURLSession *)session didBecomeInvalidWithError:(nullable NSError *)error;
- (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
                                         completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * _Nullable credential))completionHandler;
- (void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session NS_AVAILABLE_IOS(7_0);
@end

//该协议中的方法处理task层级的事件,各种类型task的公共事件
@protocol NSURLSessionTaskDelegate <NSURLSessionDelegate>
@optional
 - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
                 willPerformHTTPRedirection:(NSHTTPURLResponse *)response
                                 newRequest:(NSURLRequest *)request
                          completionHandler:(void (^)(NSURLRequest * _Nullable))completionHandler;
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
                        didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge 
                          completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * _Nullable credential))completionHandler;
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
                          needNewBodyStream:(void (^)(NSInputStream * _Nullable bodyStream))completionHandler;
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
                            didSendBodyData:(int64_t)bytesSent
                             totalBytesSent:(int64_t)totalBytesSent
                   totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend;
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didFinishCollectingMetrics:(NSURLSessionTaskMetrics *)metrics API_AVAILABLE(macosx(10.12), ios(10.0), watchos(3.0), tvos(10.0));
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
                       didCompleteWithError:(nullable NSError *)error;
@end

//该协议中的方法处理task层级(dataTask与uploadTask)的事件
@protocol NSURLSessionDataDelegate <NSURLSessionTaskDelegate>
@optional
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask
                             didReceiveResponse:(NSURLResponse *)response
                              completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler;
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask
                          didBecomeDownloadTask:(NSURLSessionDownloadTask *)downloadTask;
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask
                            didBecomeStreamTask:(NSURLSessionStreamTask *)streamTask;
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask
                                 didReceiveData:(NSData *)data;
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask
                              willCacheResponse:(NSCachedURLResponse *)proposedResponse 
                              completionHandler:(void (^)(NSCachedURLResponse * _Nullable cachedResponse))completionHandler;
@end

//该协议中的方法处理task层级(downloadTask)的事件
@protocol NSURLSessionDownloadDelegate <NSURLSessionTaskDelegate>
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask
                          didFinishDownloadingToURL:(NSURL *)location;

@optional
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask
                                       didWriteData:(int64_t)bytesWritten
                                  totalBytesWritten:(int64_t)totalBytesWritten
                          totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite;
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask
                                  didResumeAtOffset:(int64_t)fileOffset
                                 expectedTotalBytes:(int64_t)expectedTotalBytes;
@end

在后续的学习使用中,你会发现你创建了什么类型的task,那么也只会该类型taskDelegate中定义的代理事件会被触发,犹如你创建了一个NSURLSessionDownloadTask,那么只可能会触发NSURLSessionDownloadDelegate及其父协议中的方法,不可能会触发NSURLSessionDataDelegate中的代理事件。

通常来说,当你创建了一个session,并使用该session创建task并执行(一定要记得执行),那么代理方法将会想继被执行,可以参考下图

delegate001.png
delegate002.png
delegate003.png
delegate004.png
delegate005.png
delegate006.png

NSURLSessionTask

NSURLSessionTask - a cancelable object that refers to the lifetime
of processing a given request。
从描述中可以看出,它为一个处理给定网络请求的可取消对象,换句话说你可以通过NSURLSessionTask对象中声明的方法控制一个请求的开始、暂停、取消。

Tasks.png

从图中,可以看出NSURLSessionTask对象及其子类的层级结构。

  1. 我们使用NSURLSessionDataTask用于获取或上传表单数据,当你查看AFNetworking封装的GET请求,你会发现其创建了NSURLSessionDataTask对象并发起网络请求任务。

  2. 我们使用NSURLSessionUploadTask用于上传二进制数据/文件,如果当前待上传对象是内存对象,则使用传输二进制的方式便捷;如果当前待上传对象是存于沙盒中,则根据其路径的方式便捷。当你查看AFNetworking封装的POST请求,你会发现其使用了NSURLSessionUploadTask对象并发起网络请求任务。

  3. 我们使用NSURLSessionDownloadTask用于下载数据。

总结

对于使用NSURLSession发送http网络请求,通常的步骤为

创建task并执行
  1. 创建session 的配置项
    Create a session configuration. For background sessions, this configuration must contain a unique identifier. Store that identifier, and use it to reassociate with the session if your app crashes or is terminated or suspended.

  2. 根据指定的configuration object配置项对象,创建session
    Create a session, specifying a configuration object and, optionally, a delegate.

  3. 根据指定的session对象,创建符合需求类型的task并执行-[NSURLSessionTask resume]
    Create task objects within a session that each represent a resource request. These task objects are subclasses of NSURLSessionTask—NSURLSessionDataTask, NSURLSessionUploadTask, or NSURLSessionDownloadTask, depending on the behavior you are trying to achieve.

Each task starts out in a suspended state. After your app calls resume on the task, it begins downloading the specified resource.

接受数据并处理

当我们使用NSURLSession相关类发送网络请求时,我们接受响应有两种方式:

  • To a completion handler block that is called when a transfer finishes successfully or with an error.

通过异步的completion handler block回调,通过这张方式接受数据的优点是你可以直接得到最终的结果,并不需要你处理上文中提到的代理方法,缺点是你不能细颗粒度的去观察当前请求的响应情况。例如你不能获取当前的上传下载进度,你也不能做一些权限验证等操作

  • By calling methods on the session’s delegate as data is received and when the transfer is complete.

通过代理接收并处理数据,优缺点与前一种方式相反。

重要重要
你可以''同时''通过第一种方式获取并处理数据,通过第二种方式设置权限验证、进度处理等业务。
交流群 欢迎加入你所不知道的iOS交流群292898905,欢迎!!!
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,937评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,503评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,712评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,668评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,677评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,601评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,975评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,637评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,881评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,621评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,710评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,387评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,971评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,947评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,189评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,805评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,449评论 2 342

推荐阅读更多精彩内容

  • NSURLSession概述1. NSURLSession session类型NSURLSession包括下面3种...
    瞎嘚嘚阅读 1,869评论 2 2
  • 在苹果彻底弃用NSURLConnection之后自己总结的一个网上的内容,加上自己写的小Demo,很多都是借鉴网络...
    付寒宇阅读 4,259评论 2 13
  • 新工作快一年了!从各种不适应到现在的得心应手,真的是一言难尽。 一直觉得自己不够幸运,上帝从来不会眷顾我!更不会心...
    青衫亿笙阅读 331评论 0 0
  • 那些喜欢虐待感的人,大概都会喜欢天都峰这个设定 近乎垂直的的“鲫鱼背”上山,险峰深梯,全程直到下山,没有缆车。这大...
    滴落先生阅读 105评论 0 0
  • 跨年吗?看表演?看烟花?看演唱会?... 自由职业者的跨年,气氛没那么浓烈,貌似别人都很开心。那是一种什么感觉了!...
    Jeona阅读 133评论 0 2