随说 : 从解决业务方法中入手开始读源码,但是在此之前,我有个问题,为什么苹果在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负责发送和接收HTTP的请求。
- 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标头等
三种创建方式 :
// 创建一个使用磁盘坚持全局缓存,证书和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,以及上传下载文件。
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+框架中,是怎样设计这些类的使用的.