iOS (五) - AFNetworking 3.0+ 总结NSURLSession (2)

随说 : 从解决业务方法中入手开始读源码,但是在此之前,我有个问题,为什么苹果在iOS7之后引进了这个NSURLSession? ,并且AFNetworking3.x后已经将NSURLConnection废弃,我有个原则,你会用一个东西去解决一些问题之后,应该去问问自己为什么要用这个东西,AFNetworking3.x是基于NSURLSession来封装的, 现在来总结一下NSURLSession的用法
Xcode 7+ is required.NSURLConnectionOperation support has been removed

解决这个疑惑, 请你拜读以下的文章
NSURLSession 入门教程
别说你会AFNetworking3.0/NSURLSession
忘记NSURLConnection,拥抱NSURLSession吧!

1. NSURLSession是什么?##

先来看两个图

NSURLSession及其组成类

NSURLSession类中提供三个类方法创建URLSession对象
  1. NSURLSession负责发送和接收HTTP的请求。
  2. NSURLSession由NSURLSessionConfiguration(我理解为一份配置)和NSURLSessionDelegate & NSOperationQueue(一份协议)组成
    每一个NSURLSession对象都是根据一个NSURLSessionConfiguration初始化的,该NSURLSessionConfiguration指定了上面提到的政策,以及一系列为了提高移动设备性能而专门添加的新选项。
    而NSURLSession的另一重要组成部分是会话任务,它负责处理数据的加载,以及客户端与服务器之间的文件和数据的上传下载服务。NSURLSessionTask与NSURLConnection是及其相似的,因为它负责加载数据,而主要的区别在于,任务共享它们父类NSURLSession的共同委托(common delegate)。

/*
 * The shared session uses the currently set global NSURLCache,
 * NSHTTPCookieStorage and NSURLCredentialStorage objects.
 */
// 创建默认NSURLSession对象 默认使用defaultSessionConfiguration
// 使用的是全局的cache,cookie和credential storage objects来创建configuration对象
// 通过默认配置来创建一个NSURLSession并且不需要协议
+ (NSURLSession *)sharedSession;

/*
 * Customization of NSURLSession occurs during creation of a new session.
 * If you only need to use the convenience routines with custom
 * configuration options it is not necessary to specify a delegate.
 * If you do specify a delegate, the delegate will be retained until after
 * the delegate has been sent the URLSession:didBecomeInvalidWithError: message.
 */
/*
// 通过一份连接配置来创建一个NSURLSession
+ (NSURLSession *)sessionWithConfiguration:(NSURLSessionConfiguration *)configuration;

// 通过一份连接配置和一份协议来创建一个NSURLSession
+ (NSURLSession *)sessionWithConfiguration:(NSURLSessionConfiguration *)configuration delegate:(nullable id <NSURLSessionDelegate>)delegate delegateQueue:(nullable NSOperationQueue *)queue;

2. NSURLSessionConfiguration是什么?##

我理解为一份配置, 而这份配置就是储存这个整个连接的一些基本属性例如 : 会话属性,如超时值,高速缓存的政策和额外的HTTP标头等

NSURLSessionConfiguration类

三种创建方式 :

//  创建一个使用磁盘坚持全局缓存,证书和cookie的默认配置对象。
+ (NSURLSessionConfiguration *)defaultSessionConfiguration;

// 类似于默认配置,用于“private” sessions,对于cache, cookie, or credential storage objects的非永久存储。
+ (NSURLSessionConfiguration *)ephemeralSessionConfiguration;

// 让会话在后台执行上传或下载任务。当应用程序本身被暂停或终止转让甚至继续。iOS 8.0后提供的属性
// 做远程push通知或是应用程序挂起的时候就要用到这个configuration
+ (NSURLSessionConfiguration *)backgroundSessionConfigurationWithIdentifier:(NSString *)identifier NS_AVAILABLE(10_10, 8_0); 

常规配置属性 :

/* 常规属性 - 常规属性有7个  */ 
/*background 模式下需要标识 */
@property (nullable, readonly, copy) NSString *identifier;

/*超时属性 ,用作设置timeoutIntervalForRequest时间内, 如果没有请求数据发送,则请求超时 */
@property NSTimeInterval timeoutIntervalForRequest;

/* 超时属性, 用作设置timeoutIntervalForResource时间内,如果没有返回响应,则响应超时 */
@property NSTimeInterval timeoutIntervalForResource;

/* 网络服务类型 */
typedef NS_ENUM(NSUInteger, NSURLRequestNetworkServiceType)
{
    NSURLNetworkServiceTypeDefault = 0, // Standard internet traffic
    NSURLNetworkServiceTypeVoIP = 1, // Voice over IP control traffic  
    NSURLNetworkServiceTypeVideo = 2, // Video traffic
    NSURLNetworkServiceTypeBackground = 3, // Background traffic
    NSURLNetworkServiceTypeVoice = 4    // Voice data
};
// 这个属性一般用于音频处理流
@property NSURLRequestNetworkServiceType networkServiceType;

// 设置这个属性, 会为所有的NSURLSessionTask加上基础request头,可以统一请求头
@property (nullable, copy) NSDictionary *HTTPAdditionalHeaders;

// 一个布尔值,确定是否通过蜂窝网络连接, 默认为YES , 
@property BOOL allowsCellularAccess;

// iOS8.0后才能用, backgroundSessionConfigurationWithIdentifier中的identifier中对应使用, 被标识的文件,会在后台中下载
@property (nullable, copy) NSString *sharedContainerIdentifier NS_AVAILABLE(10_10, 8_0);

cookie策略配置

// NSHTTPCookieAcceptPolicy, 配置处理cookie的策略, 
typedef NS_ENUM(NSUInteger, NSHTTPCookieAcceptPolicy) {
    NSHTTPCookieAcceptPolicyAlways, // 总是接受cookie
    NSHTTPCookieAcceptPolicyNever, // 总是不接受cookie
    NSHTTPCookieAcceptPolicyOnlyFromMainDocumentDomain // 只从DocumentDomain文件中接受缓存
};
@property NSHTTPCookieAcceptPolicy HTTPCookieAcceptPolicy

// HTTPCookieStorage类, 提供了一些方法, 这个类的作用是储存请求的cookie, 待下一次请求的时候, 会再次将上次保存下来了的cookie继续去请求
@property(retain) NSHTTPCookieStorage *HTTPCookieStorage

// 一个布尔值,确定是否请求应包含来自cookie存储的cookie。The default value is YES
@property BOOL HTTPShouldSetCookies

安全策略配置

// TLSMaximumSupportedProtocol 和 TLSMinimumSupportedProtocol 确定是否支持SSLProtocol版本的会话。

/* The minimum allowable versions of the TLS protocol, from <Security/SecureTransport.h> SSL协议*/
@property SSLProtocol TLSMinimumSupportedProtocol;

/* The maximum allowable versions of the TLS protocol, from <Security/SecureTransport.h> SSL协议*/
@property SSLProtocol TLSMaximumSupportedProtocol;

// NSURLCredentialStorage类管理的是task会话中使用任务凭据存储对象。
@property(retain) NSURLCredentialStorage *URLCredentialStorage

缓存策略配置

// NSURLRequestCachePolicy枚举
typedef NS_ENUM(NSUInteger, NSURLRequestCachePolicy)
{
// 默认的缓存策略, 如果缓存不存在,直接从服务端获取。如果缓存存在,会根据response中的Cache-Control字段判断下一步操作,如: Cache-Control字段为must-revalidata, 则询问服务端该数据是否有更新,无更新的话直接返回给用户缓存数据,若已更新,则请求服务端.
    NSURLRequestUseProtocolCachePolicy = 0, 
// 忽略本地缓存数据,直接请求服务端.
    NSURLRequestReloadIgnoringLocalCacheData = 1,
// Unimplemented 未实现枚举值
    NSURLRequestReloadIgnoringLocalAndRemoteCacheData = 4, // Unimplemented
// 相当于NSURLRequestReloadIgnoringLocalCacheData, 忽略本地缓存数据,直接请求服务端.
    NSURLRequestReloadIgnoringCacheData = NSURLRequestReloadIgnoringLocalCacheData,
// 有缓存就使用,不管其有效性(即忽略Cache-Control字段), 无则请求服务端.
    NSURLRequestReturnCacheDataElseLoad = 2,
// 加载本地缓存. 有就加载, 没有就当加载失败处理. (确定当前无网络时使用)
    NSURLRequestReturnCacheDataDontLoad = 3,
// Unimplemented 未实现枚举值
    NSURLRequestReloadRevalidatingCacheData = 5, // Unimplemented
};
/* 请求的默认缓存策略 ,有以上几种方式*/
// 指定了一个请求的缓存响应的方式,和应该在什么时候返回
@property NSURLRequestCachePolicy requestCachePolicy;

/* The URL resource cache, or nil to indicate that no caching is to be performed */
// 是会话使用的缓存。默认情况下,NSURLCache 的+ sharedURLCache 会被使用
@property (nullable, retain) NSURLCache *URLCache;

设置HTTP策略和代理属性

/* The proxy dictionary, as described by <CFNetwork/CFHTTPStream.h> */
// 指定了Session(会话)连接中的代理服务器。同样地,大多数面向消费者的应用程序都不需要代理,所以基本上不需要配置这个属性。
@property (nullable, copy) NSDictionary *connectionProxyDictionary;

/* The maximum number of simultanous persistent connections per host */
// 是 Foundation 框架中URL加载系统的一个新的配置选项。它曾经被用于NSURLConnection管理私人连接池。现在有了NSURLSession,开发者可以在需要时限制连接到特定主机的数量。
@property NSInteger HTTPMaximumConnectionsPerHost;

/* Allow the use of HTTP pipelining */
// 也出现在NSMutableURLRequest,它可以被用于开启HTTP管道,这可以显着降低请求的加载时间,但是由于没有被服务器广泛支持,默认是禁用的。
@property BOOL HTTPShouldUsePipelining;

3. NSURLSessionTask是什么?##

NSURLSessionTask是一个抽象子类,它有三个具体的子类是可以直接使用的:NSURLSessionDataTask,NSURLSessionUploadTask和NSURLSessionDownloadTask。这三个类封装了现代应用程序的三个基本网络任务:获取数据,比如JSON或XML,以及上传下载文件。

Paste_Image.png

NSURLSessionTask的三个子类completionHandler处理方式有点不同
NSURLSessionDataTask (JSON或XML) :
数据在完成时立即返回,

NSURLSessionDownloadTask(下载文件) :
下载任务将数据写入本地的临时文件。completionHandler将文件从它的临时位置移动到一个永久位置,这个永久位置就是块的返回值。它会带回已下载文件的一个临时的文件路径location.

NSURLSessionUploadTask(上传文件)
因为一般来说,服务端对于一个上传任务的响应也会有相关数据返回,所以NSURLSessionUploadTask


3.1 已经有了NSURLSessionDataTask, 为什么还有继承多一层NSURLSessionUploadTask??###

从两者提供的对应task 生成的方法能看。比如使用dataTask来进行上传任务的时候,需要指定HTTPMethod为POST或PUT,并且提供的数据(NSData)得赋值给request.HTTPBody。而使用uploadTask来进行上传任务的时候,只需要使用- uploadTaskWithRequest:fromData:或- uploadTaskWithRequest:fromFile:之类的方法,其中参数的话只需要根提供数据(NSData)或者数据的磁盘位置(NSURL*fileURL)就可以构造出一个上传的session task了,简化了操作。


NSURLSessionTask 的属性

// 任务标识,唯一确定一个任务
@property (readonly)                 NSUInteger    taskIdentifier;    /* an identifier for this task, assigned by and unique to the owning session */
// 上一个请求对象
@property (nullable, readonly, copy) NSURLRequest  *originalRequest;  /* may be nil if this is a stream task */
// 当前请求对象
@property (nullable, readonly, copy) NSURLRequest  *currentRequest;   /* may differ from originalRequest due to http server redirection */
// 服务器的响应数据
@property (nullable, readonly, copy) NSURLResponse *response;         /* may be nil if no response has been received */

/* 如果不存在响应实体, 字节数可以为零 
 * or NSURLSessionTransferSizeUnknown if it is not possible 
 * to know how many bytes will be transferred.
 */

/* number of body bytes already received */
// 已经接收到的数据量
@property (readonly) int64_t countOfBytesReceived;

/* number of body bytes already sent */
// 已经发送的数据量
@property (readonly) int64_t countOfBytesSent;

/* number of body bytes we expect to send, derived from the Content-Length of the HTTP request */
// 所要发送的总数据量
@property (readonly) int64_t countOfBytesExpectedToSend;

/* number of byte bytes we expect to receive, usually derived from the Content-Length header of an HTTP response. */
// 所要接收到的总数据量
@property (readonly) int64_t countOfBytesExpectedToReceive;

/*
 * The taskDescription property is available for the developer to
 * provide a descriptive label for the task.
 */
// 任务描述.不知道用处在什么地方
@property (nullable, copy) NSString *taskDescription;

/* -cancel returns immediately, but marks a task as being canceled.
 * The task will signal -URLSession:task:didCompleteWithError: with an
 * error value of { NSURLErrorDomain, NSURLErrorCancelled }.  In some 
 * cases, the task may signal other work before it acknowledges the 
 * cancelation.  -cancel may be sent to a task that has been suspended.
 */
// 取消任务 
- (void)cancel;

/*
 * Suspending a task will prevent the NSURLSession from continuing to
 * load data.  There may still be delegate calls made on behalf of
 * this task (for instance, to report data received while suspending)
 * but no further transmissions will be made on behalf of the task
 * until -resume is sent.  The timeout timer associated with the task
 * will be disabled while a task is suspended. -suspend and -resume are
 * nestable. 
 */
// 暂停任务
- (void)suspend;

// 继续任务 / 开始任务
- (void)resume;

/*
 * The current state of the task within the session.
 */
// 会话状态,NSURLSessionTaskState 枚举 有4个状态
@property (readonly) NSURLSessionTaskState state;

/*
 * The error, if any, delivered via -URLSession:task:didCompleteWithError:
 * This property will be nil in the event that no error occured.
 */
// 错误信息 通过-URLSession:task:didCompleteWithError:来传递
@property (nullable, readonly, copy) NSError *error;


NSURLSessionDataTask 与 NSURLSessionUploadTask都没有扩展方法和属性
NSURLSessionDownloadTask 扩展了一个方法

// 提供了一个取消任务的方法,而且会保存用于以后继续任务的信息,方法如下:
- (void)cancelByProducingResumeData:(void (^)(NSData * __nullable resumeData))completionHandler;

总结一下 !##

与NSURLConnection类似,除了同名类NSURLSession,NSURLSession也是指一组相互依赖的类。NSURLSession包括与之前相同的组件,例如NSURLRequest, NSURLCache等。NSURLSession的不同之处在于,它把 NSURLConnection替换为NSURLSession, NSURLSessionConfiguration,以及3个NSURLSessionTask的子类NSURLSessionDataTask, NSURLSessionUploadTask, 和NSURLSessionDownloadTask, IOS9之后又多了一个NSURLSessionStreamTask
NSURLSession最直接的改善就是提供了配置每个会话的缓存,协议,cookie和证书政策(credential policies),甚至跨应用程序共享它们的能力. 一种很好的设计思想, 将网络基础架构和部分应用程序独立工作,互相不会干扰.

一个NSURLSession(会话), 是通过一份NSURLSessionConfiguration(对于会话如何产生请求,提供了相当多的控制和灵活性。从网络访问性能,到cookie,安全性,缓存策略,自定义协议,启动事件设置,以及用于移动设备优化的几个新属性)从而初始化一个NSURLSession(会话), 当然同时也可以遵守一些Delegate协议,从而扩展一些方法

定义NSURLSessionConfiguration(配置) - > (可选)遵守协议(NSURLSessionDelegate) ->创建NSURLSession(会话) ->根据实质需求定义NSURLSessionTask(任务)

后记 : 写文章的过程中,是对自己的思维的一个总结,翻查了很多文档,同时也交叉对比了一些文档与文章中的话,只有理解了基础, 才可以玩得很6, 下一章我将会开始扣AFNetworking 3.0+框架中,是怎样设计这些类的使用的.

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

推荐阅读更多精彩内容