iOS开发之常用技术点

NSURLSession(API篇)

2018-12-25  本文已影响26人  KinKen

前言

本文基于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的几个类型

属性、方法 解释
@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;(效果见下一行),接着在代理回调队列调用completionHandlerblock
- (void)flushWithCompletionHandler:(void (^)(void))completionHandler; 将存储器的网络缓存、cookies以及凭证写入磁盘,写入后清空存储器,接着在代理回调队列调用completionHandlerblock
- (void)getTasksWithCompletionHandler:(void (^)(NSArray<NSURLSessionDataTask *> *dataTasks, NSArray<NSURLSessionUploadTask *> *uploadTasks, NSArray<NSURLSessionDownloadTask *> *downloadTasks))completionHandler; 所有数据、上传、下载tasks完成时,在代理队列异步回调completionHandlerblock,传出一系列在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至少调用一次,当且仅当NSURLSessionConfigurationwaitsForConnectivity属性设置为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; 构造方法

十、结构关系梳理

NSURLSession梳理.png
上一篇下一篇

猜你喜欢

热点阅读