NSURLSession(API篇)
前言
本文基于NSURLSession.h接口文件以及官方文档介绍,主要了解梳理各个类中方法与属性以及协议方法,属于比较初级的理解,大部分描述来源于文档英文翻译,如觉得生硬请考虑阅读官方文档。
文章目录结构
一、官方文档介绍
二、NSURLSessionConfiguration
三、NSURLSessionConfiguration (NSURLSessionDeprecated)
四、NSURLSession
(一)、简介
(二)、NSURLSession的几个类型
五、NSURLSession (NSURLSessionAsynchronousConvenience)
六、NSURLSessionTask
(一)、NSURLSessionDataTask
(二)、NSURLSessionUploadTask
(三)、NSURLSessionDownloadTask
(四)、NSURLSessionStreamTask
七、NSURLSessionDelegate
(一)、NSURLSessionTaskDelegate
(二)、NSURLSessionDataDelegate
(三)、NSURLSessionDownloadDelegate
(四)、NSURLSessionStreamDelegate
八、NSURLSessionTaskTransactionMetrics
九、NSURLSessionTaskMetrics
十、结构关系梳理
一、官方文档介绍
以下是从NSURLSession.h文件自己翻译的的文档注释,英语水平一般,自己勉强能看懂理解
NSURLSession是一组代替NSURLConnection的网络请求API,它提供了影响NSURLRequest对象从网络中检索的策略和机制的各个方面的选项。
一个NSURLSession可能与一个代理对象绑定,这个代理对象的方法在session整个生命周期某些事件发生时会被调用,如服务器验证或者确定一个资源是否被加载并且转换成一个下载。
NSURLSession对象是线程安全的
默认的NSURLSession使用系统提供的代理,它适合用来替换以下这样的代码调用
+[NSURLConnection sendAsynchronousRequest:queue:completionHandler:]
NSURLSession创建NSURLSessionTask对象,task代表一个资源被加载的操作、行为。它比NSURLConnection提供更多的控制以及统一的代理模型
NSURLSessionTask对象被创建出来的时候总是处于挂起状态,因此需要发送-resume消息来执行task
NSURLSessionTask的子类用于在语义上区分数据任务和文件下载任务
NSURLSessionDataTask通过代理方法
URLSession:dataTask:didReceiveData:
<NSURLSessionDataDelegate>的回调接收资源数据,这是一种最常见的与检索对象相关的任务类型,以便使用者立即解析数据
NSURLSessionUploadTask在如何构建它的实例方面不同于NSURLSessionDataTask,上传任务显式地被创建,通过引用需要上传文件或数据对象或利用代理方法-
URLSession:task:needNewBodyStream:
<NSURLSessionTaskDelegate>提供一个上传body
NSURLSessionDownloadTask会直接将相应数据写成一个临时文件,写操作完成后,会向代理发送一个消息
URLSession:downloadTask:didFinishDownloadingToURL:
<NSURLSessionDownloadDelegate>,给予一次移动临时文件到沙盒的机会或直接读取。如果当前任务取消,它可以生成一个数据块用于下次断点继传
从iOS9与Mac OS X10.11开始,NSURLSessionStreamTask是一种新的可用的任务类型,它允许通过TCP/IP,可选的安全握手以及代理导航直接连接到给定的主机和端口。随着HTTP的升级以及HTTPAdditionalHeaders与HTTPShouldUsePipelining 属性选项在NSURLSessionConfiguration中的使用,Data task可能会被升级成NSURLSessionStream task
NSURLSession类和相关类提供了很多API,用于从url中下载数据并将数据上载到端点。当你的应用程序不运行时或被挂起时,这些API还能让你的应用程序执行后台下载。一组丰富的代理(<NSURLSessionDelegate>、<NSURLSessionTaskDelegate>)方法支持身份验证,并允许应用程序收到重定向等事件的通知。
二、NSURLSessionConfiguration
了解NSURLSessionConfiguration之前先看一下下面的枚举定义NSURLSessionMultipathServiceType
。
NSURLSessionMultipathServiceType
枚举定义了这些常量可用于指定多路径服务类型以关联NSURLSession。多路径服务类型决定是否尝试多路径TCP、决定在子流之间进行创建或切换的条件。使用这些服务类型需要适当的权限。如果进程没有所需的权限,则任何连接尝试都将失败。
typedef NS_ENUM(NSInteger, NSURLSessionMultipathServiceType)
{
NSURLSessionMultipathServiceTypeNone = 0, /* None - no multipath (default) */
NSURLSessionMultipathServiceTypeHandover = 1, /* Handover - secondary flows brought up when primary flow is not performing adequately. */
NSURLSessionMultipathServiceTypeInteractive = 2, /* Interactive - secondary flows created more aggressively. */
NSURLSessionMultipathServiceTypeAggregate = 3 /* Aggregate - multiple subflows used for greater bandwitdh. */
} API_AVAILABLE(ios(11.0)) API_UNAVAILABLE(macos, watchos, tvos) NS_SWIFT_NAME(URLSessionConfiguration.MultipathServiceType);
列名1 | 列名2 |
---|---|
NSURLSessionMultipathServiceTypeNone | 默认服务类型,不使用多路径TCP,连接使用单向流,设置该值不需要权限 |
NSURLSessionMultipathServiceTypeHandover | 指定仅在主子流未充分执行时才使用辅助子流。需要配置com.apple.developer.networking.multipath 权限 |
NSURLSessionMultipathServiceTypeInteractive | 指定如果主子流未充分执行(丢包,高往返时间,带宽问题),则应使用辅助子流。比那个枚举值更加aggressively,需要配置com.apple.developer.networking.multipath 权限 |
NSURLSessionMultipathServiceTypeAggregate | 指定跨多个接口的多个子流应在更好的带宽下使用。仅在开发真机调试下使用。它可以在“设置”->“开发者”部分中启用。 |
简单了解过NSURLSessionMultipathServiceType
,接着看NSURLSessionConfiguration。
NSURLSessionConfiguration是创建NSURLSession对象时需要的配置选项。在创建session时,会生成Configuration对象的副本。在创建session之后,就不能再修改session的配置,只能重新创建Configuration来生成新的session。
注意:
在某些情况下,此Configuration中定义的策略可能被为任务提供的NSURLRequest对象指定的策略覆盖。
在NSURLRequest对象上指定的任何策略都是受尊重的,除非Session的策略更具限制性。
例如,如果SessionConfiguration指定不允许蜂窝网络,NSURLRequest对象就不能请求蜂窝网络。
属性、方法 | 解释 |
---|---|
@property (class, readonly, strong) NSURLSessionConfiguration *defaultSessionConfiguration; |
默认的SessionConfiguration,会将缓存、凭据存储或任何与会话相关的数据存储到磁盘 |
@property (class, readonly, strong) NSURLSessionConfiguration *ephemeralSessionConfiguration; |
短暂性的SessionConfiguration,不将缓存、凭据存储或任何与会话相关的数据存储到磁盘。默认存储在RAM,除非手动指示它将URL内容写到一个文件 |
+ (NSURLSessionConfiguration *)backgroundSessionConfigurationWithIdentifier:(NSString *)identifier API_AVAILABLE(macos(10.10), ios(8.0), watchos(2.0), tvos(9.0)); |
通过唯一标识Identifier创建一个后台SessionConfiguration,对应创建的session允许后台执行HTTP/HTTPS上传、下载操作,通常交给系统开启一个单独的子进程处理,详细看Discussion |
@property (nullable, readonly, copy) NSString *identifier; |
返回background session configuration 的唯一identifier |
@property NSURLRequestCachePolicy requestCachePolicy; |
默认的request缓存策略 |
@property NSTimeInterval timeoutIntervalForRequest; |
request默认超时时间,数据传输时会重置 |
@property NSTimeInterval timeoutIntervalForResource; |
resource默认超时时间,资源在一定时间内没有被获取,抛出超时 |
@property NSURLRequestNetworkServiceType networkServiceType; |
request的网络服务类型 |
@property BOOL allowsCellularAccess; |
是否允许request使用蜂窝移动数据 |
@property BOOL waitsForConnectivity API_AVAILABLE(macos(10.13), ios(11.0), watchos(4.0), tvos(11.0)); |
设置网络不可用时,是否立即提示错误(如NSURLErrorNotConnectedToInternet ),等待连接时,timeoutIntervalForRequest 属性生效(不计时),但timeoutIntervalForResource 属性生效(计时)。默认值为NO, 后台Session会忽略,因为后台Session始终等待连接 |
@property (getter=isDiscretionary) BOOL discretionary API_AVAILABLE(macos(10.10), ios(7.0), watchos(2.0), tvos(9.0)); |
是否允许根据系统自行决定安排后台任务,以获得最佳性能。 |
@property (nullable, copy) NSString *sharedContainerIdentifier API_AVAILABLE(macos(10.10), ios(8.0), watchos(2.0), tvos(9.0)); |
后台Session应该下载的文件的共享数据容器的标识符,应用扩展需要使用后台Session一定要设置该属性为有效的标识符,否则在传输时,session会失败(抛出NSURLErrorBackgroundSessionRequiresSharedContainer ) |
@property BOOL sessionSendsLaunchEvents API_AVAILABLE(ios(7.0), watchos(2.0), tvos(9.0)) API_UNAVAILABLE(macos); |
当后台session完成任务或需要认证时,允许在后台的应用恢复或者运行。仅应用于通过+backgroundSessionConfigurationWithIdentifier: 创建的configurations,默认值为YES |
@property (nullable, copy) NSDictionary *connectionProxyDictionary; |
包含有关在此session中使用的代理的信息的字典,默认为NULL,使用系统设置。 |
@property SSLProtocol TLSMinimumSupportedProtocol; |
最小TLS协议版本,from<Security/SecureTransport.h> ,下同 |
@property SSLProtocol TLSMaximumSupportedProtocol; |
最大TLS协议版本 |
@property BOOL HTTPShouldUsePipelining; |
是否允许使用HTTP流水线 |
@property BOOL HTTPShouldSetCookies; |
是否允许session为request设置cookies |
@property NSHTTPCookieAcceptPolicy HTTPCookieAcceptPolicy; |
接收Cookies的策略,将覆盖cookie存储指定的策略 |
@property (nullable, copy) NSDictionary *HTTPAdditionalHeaders; |
为将要发送的请求指定额外的headers,仅指定目前没有的 |
@property NSInteger HTTPMaximumConnectionsPerHost; |
每个主机的最大并发持久连接数 |
@property (nullable, retain) NSHTTPCookieStorage *HTTPCookieStorage; |
要使用的cookie存储对象,或者nil表示不应处理cookie |
@property (nullable, retain) NSURLCredentialStorage *URLCredentialStorage; |
凭证存储对象,或nil表示不使用凭证存储 |
@property (nullable, retain) NSURLCache *URLCache; |
URL资源缓存,或nil表示不执行缓存 |
@property BOOL shouldUseExtendedBackgroundIdleMode API_AVAILABLE(macos(10.11), ios(9.0), watchos(2.0), tvos(9.0)); |
为创建的任何tcp套接字启用扩展后台空闲模式。启用此模式会要求系统保持套接字打开,并在进程移至后台时延迟回收套接字 |
@property (nullable, copy) NSArray<Class> *protocolClasses; |
一组额外的协议子类,用于扩展网络协议,处理会话中的请求。 |
@property NSURLSessionMultipathServiceType multipathServiceType API_AVAILABLE(ios(11.0)) API_UNAVAILABLE(macos, watchos, tvos); |
用于连接的多路径服务类型。 默认值为NSURLSessionMultipathServiceTypeNone
|
三、NSURLSessionConfiguration (NSURLSessionDeprecated)
NSURLSessionConfiguration的分类,只有一个方法,现在不建议使用,取代它的是原类里的
+ (NSURLSessionConfiguration *)backgroundSessionConfigurationWithIdentifier:(NSString *)identifier API_AVAILABLE(macos(10.10), ios(8.0), watchos(2.0), tvos(9.0));
+ (NSURLSessionConfiguration *)backgroundSessionConfiguration:(NSString *)identifier NS_DEPRECATED(NSURLSESSION_AVAILABLE, 10_10, 7_0, 8_0, "Please use backgroundSessionConfigurationWithIdentifier: instead");
四、NSURLSession
(一)、简介
协调一组相关网络数据传输任务的对象。
NSURLSession类和相关类提供了一个API,用于从URL指示的端点下载数据并将数据上载到端点。该API还可让您的应用在您的应用未运行时执行后台下载,或者在iOS中,在您的应用暂停时执行后台下载。一组丰富的代理方法支持身份验证,并允许您的应用程序收到重定向等事件的通知。
(二)、NSURLSession的几个类型
-
单例session,没有内置configuration,用在比较基础的请求,当连接请求要求不高的一般使用此session,通过
sharedSession
获取 - 默认session,行为与单例session非常相似,但允许更多配置,并允许您使用委托/代理逐步获取数据。
- 临时session,类似于单例session,但不会将缓存,cookie或凭据写入磁盘。
-
后台session,您可以在应用没有运行时在后台执行内容上传和下载。
第一个通过类方法获取,后三个通过传入对应的NSURLSessionConfiguration
实例化NSURLSession
获取
属性、方法 | 解释 |
---|---|
@property (class, readonly, strong) NSURLSession *sharedSession; |
获取单例session ,主要完成一些简单网络请求,无需Configuration和delegate,系统默认使用全局NSURLCache、NSHTTPCookieStorage、NSURLCredentialStorage对象 |
+ (NSURLSession *)sessionWithConfiguration:(NSURLSessionConfiguration *)configuration; |
根据NSURLSessionConfiguration 自定义NSURLSession |
+ (NSURLSession *)sessionWithConfiguration:(NSURLSessionConfiguration *)configuration delegate:(nullable id <NSURLSessionDelegate>)delegate delegateQueue:(nullable NSOperationQueue *)queue; |
根据NSURLSessionConfiguration 自定义NSURLSession,同时指定一个回调的代理以及代理方法在哪个队列回调。代理会被一直强引用直至向代理发送一个URLSession:didBecomeInvalidWithError: 消息,如果网络请求简单,可以不指定代理。 |
@property (readonly, retain) NSOperationQueue *delegateQueue; |
返回当前session指定的代理回调队列 |
@property (nullable, readonly, retain) id <NSURLSessionDelegate> delegate; |
返回当前session指定的代理,根据官方文档:session对象会强引用代理对象直至App退出或显式废弃(释放)session,否则会导致内存泄漏 |
@property (readonly, copy) NSURLSessionConfiguration *configuration; |
返回当前session的NSURLConfiguration 配置 |
@property (nullable, copy) NSString *sessionDescription; |
允许我们给session提供一个描述性的标签 |
- (void)finishTasksAndInvalidate; |
调用该方法会立即返回,当前存在的tasks接下来会被执行完成,此时不能再创建新的tasks,session会继续回调代理方法直至向代理发送URLSession:didBecomeInvalidWithError: 消息。该方法与-invalidateAndCancel 方法(在下一行)对单例session无效。当释放了后台session而且没有回调代理方法URLSession:didBecomeInvalidWithError: 再用相同的identifier创建新的后台session是不安全的。 |
- (void)invalidateAndCancel; |
该方法跟-finishTasksAndInvalidate 类似,不过是取消当前存在的tasks,注意任务取消取决于任务的状态,并且某些任务可能在发-cancel 时已经完成。 |
- (void)resetWithCompletionHandler:(void (^)(void))completionHandler; |
清空当前网络缓存、cookies、凭证存储,删除当前磁盘相关文件,- (void)flushWithCompletionHandler:(void (^)(void))completionHandler; (效果见下一行),接着在代理回调队列调用completionHandler block |
- (void)flushWithCompletionHandler:(void (^)(void))completionHandler; |
将存储器的网络缓存、cookies以及凭证写入磁盘,写入后清空存储器,接着在代理回调队列调用completionHandler block |
- (void)getTasksWithCompletionHandler:(void (^)(NSArray<NSURLSessionDataTask *> *dataTasks, NSArray<NSURLSessionUploadTask *> *uploadTasks, NSArray<NSURLSessionDownloadTask *> *downloadTasks))completionHandler; |
所有数据、上传、下载tasks完成时,在代理队列异步回调completionHandler block,传出一系列在session创建的tasks,不包括已完成、已取消、已失败 后失效的tasks |
- (void)getAllTasksWithCompletionHandler:(void (^)(NSArray<__kindof NSURLSessionTask *> *tasks))completionHandler API_AVAILABLE(macos(10.11), ios(9.0), watchos(2.0), tvos(9.0)); |
效果同上,只不过是block的参数数组包含了所有类型的tasks |
- (NSURLSessionDataTask *)dataTaskWithRequest:(NSURLRequest *)request; |
根据给出的request创建data task,request可能包含body stream |
- (NSURLSessionDataTask *)dataTaskWithURL:(NSURL *)url; |
根据给出的url创建data task |
- (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)request fromFile:(NSURL *)fileURL; |
根据给出的request与文件URL(用于创建请求体)创建upload task |
- (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)request fromData:(NSData *)bodyData; |
根据给出的request与bodyData(用于创建请求体)创建upload task |
- (NSURLSessionUploadTask *)uploadTaskWithStreamedRequest:(NSURLRequest *)request; |
根据给出的StreamdRequest 创建upload task,先前request内的请求体流如果存在会被覆盖,当请求体负荷被要求时,代理方法URLSession:task:needNewBodyStream: 会被调用(The previously set body stream of the request (if any) is ignored and the URLSession:task:needNewBodyStream: delegate will be called when the body payload is required.) |
- (NSURLSessionDownloadTask *)downloadTaskWithRequest:(NSURLRequest *)request; |
根据给出的request创建download task |
- (NSURLSessionDownloadTask *)downloadTaskWithURL:(NSURL *)url; |
根据给出的url创建download task |
- (NSURLSessionDownloadTask *)downloadTaskWithResumeData:(NSData *)resumeData; |
根据之前保存的resume data恢复download task,如果恢复失败,回调代理方法URLSession:task:didCompleteWithError:
|
- (NSURLSessionStreamTask *)streamTaskWithHostName:(NSString *)hostname port:(NSInteger)port API_AVAILABLE(macos(10.11), ios(9.0), tvos(9.0)) __WATCHOS_PROHIBITED; |
根据给出的主机名、端口号创建bidirectional stream task(双向流任务) |
- (NSURLSessionStreamTask *)streamTaskWithNetService:(NSNetService *)service API_AVAILABLE(macos(10.11), ios(9.0), tvos(9.0)) __WATCHOS_PROHIBITED; |
根据给出的NSNetService创建双向流任务以标识端点。在IO完成之前,会解析NSNetService |
五、NSURLSession (NSURLSessionAsynchronousConvenience)
这个分类主要提供了一些方便请求回调的方法,基本上是通过block来回调传递服务器数据、响应信息,以及请求错误。后台session不能使用这些方法来回调请求结果
方法 | 解释 |
---|---|
- (NSURLSessionDataTask *)dataTaskWithRequest:(NSURLRequest *)request completionHandler:(void (^)(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error))completionHandler; |
根据request创建data task的简便方法,方法创建的task会绕过代理回调响应信息以及数据交付,通过提供一个简单的可取消的异步回调接口(也就是block)接收数据。错误信息会在NSURLErrorDomain <<Foundation/NSURLError.h>>返回。如果创建session时指定了代理,当接收到authentication challenges (认证挑战)时,代理方法仍然会被调用 |
- (NSURLSessionDataTask *)dataTaskWithURL:(NSURL *)url completionHandler:(void (^)(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error))completionHandler; |
根据url创建data task的简便方法,其他同上 |
- (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)request fromFile:(NSURL *)fileURL completionHandler:(void (^)(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error))completionHandler; |
request、fileURL -> upload task,效果同第一行 |
- (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)request fromData:(nullable NSData *)bodyData completionHandler:(void (^)(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error))completionHandler; |
request、bodyData -> upload task,效果同第一行 |
- (NSURLSessionDownloadTask *)downloadTaskWithRequest:(NSURLRequest *)request completionHandler:(void (^)(NSURL * _Nullable location, NSURLResponse * _Nullable response, NSError * _Nullable error))completionHandler; |
request -> download task,效果同第一行,其中location表示下载文件的URL,下载的文件在tmp临时文件夹,需要手动移动或复制到沙盒内其他文件夹,否则会被定时清除 |
- (NSURLSessionDownloadTask *)downloadTaskWithURL:(NSURL *)url completionHandler:(void (^)(NSURL * _Nullable location, NSURLResponse * _Nullable response, NSError * _Nullable error))completionHandler; |
url -> download task,效果同第一行,其中location表示下载文件的URL |
- (NSURLSessionDownloadTask *)downloadTaskWithResumeData:(NSData *)resumeData completionHandler:(void (^)(NSURL * _Nullable location, NSURLResponse * _Nullable response, NSError * _Nullable error))completionHandler; |
resumeData -> download task,效果同第一行,其中location表示下载文件的URL |
六、NSURLSessionTask
在了解各种NSURLSessionTask之前先看一下它们的继承关系:
NSURLSessionTask及其子类继承关系
从NSURLSessionTask开始,先看一下NSURLSessionTask
的几个状态
typedef NS_ENUM(NSInteger, NSURLSessionTaskState) {
NSURLSessionTaskStateRunning = 0, /* The task is currently being serviced by the session */
NSURLSessionTaskStateSuspended = 1,
NSURLSessionTaskStateCanceling = 2, /* The task has been told to cancel. The session will receive a URLSession:task:didCompleteWithError: message. */
NSURLSessionTaskStateCompleted = 3, /* The task has completed and the session will receive no more delegate notifications */
} NS_ENUM_AVAILABLE(NSURLSESSION_AVAILABLE, 7_0);
值 | 含义 |
---|---|
NSURLSessionTaskStateRunning | session正在执行的task状态 |
NSURLSessionTaskStateSuspended | task挂起状态 |
NSURLSessionTaskStateCanceling | task被取消,session会接收到一个URLSession:task:didCompleteWithError: 消息 |
NSURLSessionTaskStateCompleted | task已完成状态,session不会再接收到该task的相关代理回调 |
注意:task刚被创建时处于
NSURLSessionTaskStateSuspended
状态,因此需要显式调用-resume
来让session启动执行这个task
属性、方法 | 解释 |
---|---|
@property (readonly) NSUInteger taskIdentifier; |
task的唯一标识,由隶属的session分配 |
@property (nullable, readonly, copy) NSURLRequest *originalRequest; |
创建task时的request,如果当前task为stream task,request可能为nil |
@property (nullable, readonly, copy) NSURLRequest *currentRequest; |
由于http服务器重定向,可能与originalRequest不同 |
@property (nullable, readonly, copy) NSURLResponse *response; |
执行task后的响应信息,可能为nil |
@property (readonly, strong) NSProgress *progress API_AVAILABLE(macos(10.13), ios(11.0), watchos(4.0), tvos(11.0)); |
代表task执行进度,常用于task进度追踪 |
@property (nullable, copy) NSDate *earliestBeginDate API_AVAILABLE(macos(10.13), ios(11.0), watchos(4.0), tvos(11.0)); |
指定一个日期,在此日期前不启动网络加载执行task,没有指定则不使用启动延迟,只对后台session有效,其余session均无效 |
@property int64_t countOfBytesClientExpectsToSend API_AVAILABLE(macos(10.13), ios(11.0), watchos(4.0), tvos(11.0)); |
客户端期望从task发送的字节数(最大期望上限)。这些值用于系统调度策略。如果未指定,则使用NSURLSessionTransferSizeUnknown (-1LL) |
@property int64_t countOfBytesClientExpectsToReceive API_AVAILABLE(macos(10.13), ios(11.0), watchos(4.0), tvos(11.0)); |
客户端期望从task回调中接收到的字节数(最大期望上限)。这些值用于系统调度策略。如果未指定,则使用NSURLSessionTransferSizeUnknown (-1LL) |
@property (readonly) int64_t countOfBytesReceived; |
已接收数据的字节数 |
@property (readonly) int64_t countOfBytesSent; |
已发送数据的字节数 |
@property (readonly) int64_t countOfBytesExpectedToSend; |
客户端希望发送的正文字节数,派生自HTTP请求的Content-Length |
@property (readonly) int64_t countOfBytesExpectedToReceive; |
客户端希望接收的字节字节数,派生自HTTP响应的Content-Length头 |
@property (nullable, copy) NSString *taskDescription; |
允许我们给task提供一个描述性的标签 |
- (void)cancel; |
立即取消task执行,并且标记其为取消状态,发送一个包含{ NSURLErrorDomain, NSURLErrorCancelled } 错误的-URLSession:task:didCompleteWithError: 消息。-cancel 消息,可以发送给挂起状态的task |
@property (readonly) NSURLSessionTaskState state; |
当前session中task的状态 |
@property (nullable, readonly, copy) NSError *error; |
如果task存在error,通过-URLSession:task:didCompleteWithError: 交付。一般情况下为nil |
- (void)suspend; |
挂起task,不再执行。仍可以回调代理方法,如在挂起时报告已接收到的数据。在-resume 之前,不会再传输数据。task暂停时,将禁用与task关联的超时计时器。 |
- (void)resume; |
与- (void)suspend; 对应 |
@property float priority API_AVAILABLE(macos(10.10), ios(8.0), watchos(2.0), tvos(9.0)); |
设置task优先级,范围0~1,任何时候都可以使用此API更改task的优先级,但不是全部协议支持这个;在这些情况下,将使用生效的最后一个优先级。 |
(一)、NSURLSessionDataTask
NSURLSessionDataTask不提供NSURLSessionTask的任何附加功能,它的存在仅仅是为了提供与下载和上传任务的词汇区别。
(二)、NSURLSessionUploadTask
NSURLSessionUploadTask当前不提供NSURLSessionDataTask的任何其他功能。NSURLSessionDataTask发送的代理消息同样适用于NSURLSessionUploadTask
(三)、NSURLSessionDownloadTask
NSURLSessionDownloadTask是表示下载到本地存储的任务。
其中有一个方法,用于在取消下载任务时通过block的形式将resumeData传出去,供下一次恢复下载的时候利用,通过-downloadTaskWithResumeData:
方法利用resumeData实现断点续传
- (void)cancelByProducingResumeData:(void (^)(NSData * _Nullable resumeData))completionHandler;
(四)、NSURLSessionStreamTask
NSURLSessionStreamTask提供了一个接口,用于对通过NSURLSession创建的TCP/IP流执行读写操作。
NSURLSessionStreamTask可用于执行异步读取和写入。读取和写入是按顺序排列和执行的,并在session代理回调队列上回调completionHandler block。如果发生错误或任务被取消,则所有未完成的读写调用都将通过回调completionHandler block传出这个错误或其他信息。也可以从NSURLSessionStreamTask中通过调用-captureStreams
创建NSInputStream 和 NSOutputStream
实例。在创建流之前完成所有未完成的读取和写入。将流传递给session代理后,该任务将被视为已完成,并且不会再收到任何消息。这些流与session接触关联。
方法 | 解释 |
---|---|
- (void)readDataOfMinLength:(NSUInteger)minBytes maxLength:(NSUInteger)maxBytes timeout:(NSTimeInterval)timeout completionHandler:(void (^) (NSData * _Nullable data, BOOL atEOF, NSError * _Nullable error))completionHandler; |
读取给出的数据最小字节数或最大字节数,通过completion handler block将数据,末尾,错误信息回调出去 |
- (void)writeData:(NSData *)data timeout:(NSTimeInterval)timeout completionHandler:(void (^) (NSError * _Nullable error))completionHandler; |
通过底层socket立即写数据,如果在超时时间内所有数据字节没写完,就会报超时错误。block回调时不会保证远程端已接收到所有数据字节,only that they have been written to the kernel. |
- (void)captureStreams; |
该方法完成所有在队列中的读写操作,接着调用URLSession:streamTask:didBecomeInputStream:outputStream: 代理方法。当代理方法消息被接收,task对象就被认为已完成且不会再接收任何代理消息 |
- (void)closeWrite; |
队列加入一个请求以关闭底层socket写入端。所有当前未完成的IO操作会在关闭前完成。但是服务端可能会继续向客户端写数据,所以最好的做法是继续从服务端读取数据直至接收到EOF结尾符 |
- (void)closeRead; |
队列加入一个请求以关闭底层socket读取端。所有当前未完成的IO操作会在关闭前完成。可以继续向服务器写数据 |
- (void)startSecureConnection; |
开始已加密的🤝,🤝会在所有等待的IO完成后开始。TLS认证回调会被发送到session的代理方法-URLSession:task:didReceiveChallenge:completionHandler:
|
- (void)stopSecureConnection; |
所有等待的IO完成后,安全关闭认证连接 |
七、NSURLSessionDelegate
在了解各种NSURLSessionDelegate协议之前先看一下它们的继承关系:
几个delegate的继承关系图
在了解NSURLSessionDelegate之前先简单看一下在它之前定义的三个枚举类型,这些枚举类型会在代理方法中用到:
NSURLSessionDelayedRequestDisposition:延时URL任务采取的操作
typedef NS_ENUM(NSInteger, NSURLSessionDelayedRequestDisposition) {
NSURLSessionDelayedRequestContinueLoading = 0, /* Use the original request provided when the task was created; the request parameter is ignored. */
NSURLSessionDelayedRequestUseNewRequest = 1, /* Use the specified request, which may not be nil. */
NSURLSessionDelayedRequestCancel = 2, /* Cancel the task; the request parameter is ignored. */
} NS_SWIFT_NAME(URLSession.DelayedRequestDisposition) API_AVAILABLE(macos(10.13), ios(11.0), watchos(4.0), tvos(11.0));
值 | 含义 |
---|---|
NSURLSessionDelayedRequestContinueLoading | 任务使用原始request继续请求 |
NSURLSessionDelayedRequestUseNewRequest | 任务使用新的request继续请求 |
NSURLSessionDelayedRequestCancel | 取消任务不再请求 |
NSURLSessionAuthChallengeDisposition:session或task代理传给回调block来响应身份验证挑战
typedef NS_ENUM(NSInteger, NSURLSessionAuthChallengeDisposition) {
NSURLSessionAuthChallengeUseCredential = 0, /* Use the specified credential, which may be nil */
NSURLSessionAuthChallengePerformDefaultHandling = 1, /* Default handling for the challenge - as if this delegate were not implemented; the credential parameter is ignored. */
NSURLSessionAuthChallengeCancelAuthenticationChallenge = 2, /* The entire request will be canceled; the credential parameter is ignored. */
NSURLSessionAuthChallengeRejectProtectionSpace = 3, /* This challenge is rejected and the next authentication protection space should be tried; the credential parameter is ignored. */
} NS_ENUM_AVAILABLE(NSURLSESSION_AVAILABLE, 7_0);
值 | 含义 |
---|---|
NSURLSessionAuthChallengeUseCredential | 使用指定的凭证,可能为nil |
NSURLSessionAuthChallengePerformDefaultHandling | 对挑战使用默认处理,就好像这个委托方法没有实现一样。所提供的凭据参数将被忽略。 |
NSURLSessionAuthChallengeCancelAuthenticationChallenge | 取消整个请求。所提供的凭据参数将被忽略。 |
NSURLSessionAuthChallengeRejectProtectionSpace | 拒绝此挑战,并使用下一个身份验证保护空间再次调用身份验证委托方法。所提供的凭据参数将被忽略。 |
NSURLSessionResponseDisposition:表示一个数据或上传session task在接收到response headers时如何操作
typedef NS_ENUM(NSInteger, NSURLSessionResponseDisposition) {
NSURLSessionResponseCancel = 0, /* Cancel the load, this is the same as -[task cancel] */
NSURLSessionResponseAllow = 1, /* Allow the load to continue */
NSURLSessionResponseBecomeDownload = 2, /* Turn this request into a download */
NSURLSessionResponseBecomeStream API_AVAILABLE(macos(10.11), ios(9.0), watchos(2.0), tvos(9.0)) = 3, /* Turn this task into a stream task */
} NS_ENUM_AVAILABLE(NSURLSESSION_AVAILABLE, 7_0);
值 | 含义 |
---|---|
NSURLSessionResponseCancel | 取消请求,相当于task的cancel 方法 |
NSURLSessionResponseAllow | 运行请求操作继续执行 |
NSURLSessionResponseBecomeDownload | 将该请求任务的响应作为download task响应处理 |
NSURLSessionResponseBecomeStream | 将该请求任务的响应作为stream task响应处理 |
接下来了解NSURLSessionDelegate
NSURLSessionDelegate 定义session 代理响应的一系列方法,主要是基础连接认证以及task请求后响应的处理方法两方面
方法 | 解释 |
---|---|
- (void)URLSession:(NSURLSession *)session didBecomeInvalidWithError:(nullable NSError *)error; |
Session最后接收到的消息。session只会因系统错误或显式令其不可用而释放,后者错误参数为nil |
- (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * _Nullable credential))completionHandler; |
在发生连接级别的身份验证质询时,可以通过该代理方法提供身份验证凭据。某些类型的身份验证将应用于与服务器的给定连接上的多个请求(SSL服务器信任质询)。如果未实现此代理方法,则行为将使用默认处理,这可能涉及用户交互。block的第一个参数用到了上面提到的枚举类型,表示如何响应该身份验证质询 |
- (void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session API_AVAILABLE(ios(7.0), watchos(2.0), tvos(9.0)) API_UNAVAILABLE(macos); |
如果App接收-application:handleEventsForBackgroundURLSession:completionHandler: 消息,session的代理会接收到该方法消息,表示先前在队列中的所有消息已经交付。此时可以调用之前保存的回调(completion handler),或者开始一些内部更新操作来回调(completion handler) |
(一)、NSURLSessionTaskDelegate
方法 | 解释 |
---|---|
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task willBeginDelayedRequest:(NSURLRequest *)request completionHandler:(void (^)(NSURLSessionDelayedRequestDisposition disposition, NSURLRequest * _Nullable newRequest))completionHandler API_AVAILABLE(macos(10.13), ios(11.0), watchos(4.0), tvos(11.0)); |
当系统准备执行一个延时任务时会被调用,completionHandler block一定会被调用来处理这个request,具体查看NSURLSessionDelayedRequestDisposition枚举 |
- (void)URLSession:(NSURLSession *)session taskIsWaitingForConnectivity:(NSURLSessionTask *)task API_AVAILABLE(macos(10.13), ios(11.0), watchos(4.0), tvos(11.0)); |
当网络连接不可用,任务不能开始时调用该代理方法,该方法对于每个task至少调用一次,当且仅当NSURLSessionConfiguration 的waitsForConnectivity 属性设置为YES调用,后台session永不调用该方法,因为会忽略waitForConnectivity 这个属性 |
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task willPerformHTTPRedirection:(NSHTTPURLResponse *)response newRequest:(NSURLRequest *)request completionHandler:(void (^)(NSURLRequest * _Nullable))completionHandler; |
HTTP请求尝试重定向时调用该方法,您必须调用完成例程以允许重定向,允许使用已修改的请求进行重定向,或者将nil传递给completionHandler,以使重定向响应的主体作为此请求的有效负载传递。默认值是遵循重定向。后台session的tasks不会调用该方法。 |
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * _Nullable credential))completionHandler; |
任务收到请求特定的身份验证质询时调用。如果没有实现,session指定的身份验证质询将不会被调用,采用NSURLSessionAuthChallengeDisposition 枚举类型的默认值处理 |
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task needNewBodyStream:(void (^)(NSInputStream * _Nullable bodyStream))completionHandler; |
当task需要一个新的、未打开的body stream时调用。当涉及body stream的任何请求的身份验证失败时起到作用。 |
- (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)); |
当task完成收集统计信息时调用 |
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(nullable NSError *)error; |
task完成时调用,error一般为nil |
(二)、NSURLSessionDataDelegate
交付数据的相关代理方法
方法 | 解释 |
---|---|
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler; |
task收到response响应且在block回调前不会再收到其他信息时调用,block的第一个参数配置允许你取消request或者将data task转换成download task来处理。该代理方法是可选的,如果没有实现,可以根据task的response属性来获取响应信息。该代理方法会默认取消当前请求,因此需要调用completionHandler来处理接下来的请求,一般用NSURLSessionResponseAllow 来继续请求。 |
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didBecomeDownloadTask:(NSURLSessionDownloadTask *)downloadTask; |
通知一下,该data task变成了download task |
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didBecomeStreamTask:(NSURLSessionStreamTask *)streamTask; |
通知一下,该data task变成了stream task |
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data; |
数据开始返回且可用时调用。代理不会复制数据,只会引用,因为数据可能不连续,所以可以调用[NSData enumerateByteRangesUsingBlock:] 来访问这些数据 |
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask willCacheResponse:(NSCachedURLResponse *)proposedResponse completionHandler:(void (^)(NSCachedURLResponse * _Nullable cachedResponse))completionHandler; |
询问代理data task(或uploadtask)是否应该存储response到cache |
(三)、NSURLSessionDownloadDelegate
定义接收的数据写入文件完成后通知代理调用的相关方法
方法 | 解释 |
---|---|
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location; |
当下载任务完成时调用,在此代理方法内应该将下载的文件复制或移动到自己需要的位置,因为下次再调用时会移除上一次的下载文件记录。 |
- (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; |
下载任务断点续传恢复下载后调用 |
(四)、NSURLSessionStreamDelegate
方法 | 解释 |
---|---|
- (void)URLSession:(NSURLSession *)session readClosedForStreamTask:(NSURLSessionStreamTask *)streamTask; |
表示连接的读取端已关闭 |
- (void)URLSession:(NSURLSession *)session writeClosedForStreamTask:(NSURLSessionStreamTask *)streamTask; |
表示链接的写入端已关闭 |
- (void)URLSession:(NSURLSession *)session writeClosedForStreamTask:(NSURLSessionStreamTask *)streamTask; |
当发现有更好的连接环境时调用,如从LTE切换到了WIFI状态,但是在新环境中可能会连接失败 |
- (void)URLSession:(NSURLSession *)session streamTask:(NSURLSessionStreamTask *)streamTask didBecomeInputStream:(NSInputStream *)inputStream outputStream:(NSOutputStream *)outputStream; |
给定的task已经完成,底层网络创建了未打开的NSInputStream和NSOutputStream实例,该方法仅会在队列中所有的IO(包括必要的hankshakes)完成后调用。在此之后streamTask不会再接收代理消息 |
八、NSURLSessionTaskTransactionMetrics
该类定义在任务执行期间为请求/响应事务收集的性能指标。
方法、属性 | 解释 |
---|---|
@property (copy, readonly) NSURLRequest *request; |
request |
@property (nullable, copy, readonly) NSURLResponse *response; |
respones,请求出错时或没有内容返回为nil |
@property (nullable, copy, readonly) NSDate *fetchStartDate; |
返回用户代理开始请求获取资源的时间 |
@property (nullable, copy, readonly) NSDate *domainLookupStartDate; |
返回用户代理开始对资源进行名称查找之前的时间。 |
@property (nullable, copy, readonly) NSDate *domainLookupEndDate; | |
返回名称查找完成后的时间。 | |
@property (nullable, copy, readonly) NSDate *connectStartDate; |
返回用户代理开始与服务器建立连接时间。 |
@property (nullable, copy, readonly) NSDate *secureConnectionStartDate; |
加密连接握手验证时的时间 |
@property (nullable, copy, readonly) NSDate *secureConnectionEndDate; |
加密连接握手验证完成时的时间 |
@property (nullable, copy, readonly) NSDate *connectEndDate; |
用户代理与服务器建立连接(包括一系列握手认证)完成后的时间 |
@property (nullable, copy, readonly) NSDate *requestStartDate; |
request开始时间 |
@property (nullable, copy, readonly) NSDate *requestEndDate; |
request完成时间 |
@property (nullable, copy, readonly) NSDate *responseStartDate; |
response开始时间 |
@property (nullable, copy, readonly) NSDate *responseEndDate; |
response结束时间 |
@property (nullable, copy, readonly) NSString *networkProtocolName; |
使用的HTTP协议 |
@property (assign, readonly, getter=isProxyConnection) BOOL proxyConnection; |
请求资源是否通过代理连接 |
@property (assign, readonly, getter=isReusedConnection) BOOL reusedConnection; |
是否使用持久连接 |
@property (assign, readonly) NSURLSessionTaskMetricsResourceFetchType resourceFetchType; |
资源获取的来源,对应NSURLSessionTaskMetricsResourceFetchType 枚举值 |
-(instancetype)init; |
构造方法 |
NSURLSessionTaskMetricsResourceFetchType枚举如下:
typedef NS_ENUM(NSInteger, NSURLSessionTaskMetricsResourceFetchType) {
NSURLSessionTaskMetricsResourceFetchTypeUnknown,
NSURLSessionTaskMetricsResourceFetchTypeNetworkLoad, //资源是在网络上加载的/* The resource was loaded over the network. */
NSURLSessionTaskMetricsResourceFetchTypeServerPush, //资源是服务器推送到客户端的/* The resource was pushed by the server to the client. */
NSURLSessionTaskMetricsResourceFetchTypeLocalCache, //资源是从本地存储中获取的/* The resource was retrieved from the local storage. */
} API_AVAILABLE(macosx(10.12), ios(10.0), watchos(3.0), tvos(10.0));
九、NSURLSessionTaskMetrics
Task的任务性能指标
方法、属性 | 解释 |
---|---|
@property (copy, readonly) NSArray<NSURLSessionTaskTransactionMetrics *> *transactionMetrics; |
task中的request、response的性能指标 |
@property (copy, readonly) NSDateInterval *taskInterval; |
task初始化到完成状态的时间间隔 |
@property (assign, readonly) NSUInteger redirectCount; |
重定向的记录次数 |
-(instancetype)init; |
构造方法 |