NSURLSession(API篇)

作者: KinKen | 来源:发表于2018-12-25 00:55 被阅读26次

    前言

    本文基于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;(效果见下一行),接着在代理回调队列调用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

    相关文章

      网友评论

        本文标题:NSURLSession(API篇)

        本文链接:https://www.haomeiwen.com/subject/lghokqtx.html