网络请求之NSURLSession(api篇)

一、NSURLSession介绍

NSURLSession是协调一组网络数据传输任务的对象。(线程安全)

NSURLSession类和相关类提供了用于下载内容的API。这些API提供了一组丰富的委托方法来支持身份验证,并使应用能够在应用未运行时或者暂停应用时执行后台下载。

NSURLSession类支持数据,文件,ftp,http和https URL方案,透明支持代理服务器和SOCKS网关,如配置用户系统偏好设置的那样。

还可以使用NSURLProtocol添加对自己的自定义网络协议和URL方案的支持(以供应用程序私人使用)。

像大多数网络API一样,NSURLSession API是高度异步的。它以两种方式之一将数据返回给您的应用程序,具体取决于您调用的方法:
1、通过在传输成功完成或发生错误时调用完成处理程序块。
2、通过在收到数据和传输完成时调用会话委托中的方法。

二、API

1、创建对象 三种方式
// 一个单利对象
@property (class, readonly, strong) NSURLSession *sharedSession;

// 自定义对象
+ (NSURLSession *)sessionWithConfiguration:(NSURLSessionConfiguration *)configuration;
+ (NSURLSession *)sessionWithConfiguration:(NSURLSessionConfiguration *)configuration delegate:(nullable id <NSURLSessionDelegate>)delegate delegateQueue:(nullable NSOperationQueue *)queue;
sharedSession:

对于基本的请求,URL会话类提供了一个单例会话对象,提供合理的默认行为。由于是系统提供的对象,缺点如下:
1、无法逐步获取数据
2、没有自定义默认连接行为
3、执行身份验证的能力有限
4、应用未运行时,无法执行后台下载或上传。

自定义对象:

configuration:如缓存策略,超时,代理,流水线,支持的TLS版本,cookie策略和凭证存储。

delegate:委托对象负责处理身份验证,进行缓存决策以及处理其他会话相关事件。如果为nil,则只能用于使用完成处理程序的方法completionHandler。(block和delegate的区分)

注意:
会话对象保持对委托的强引用,直到应用退出或明确的使会话失效。 如果没有通过调用invalidateAndCancel或finishTasksAndInvalidate方法使会话失效,那么应用程序会泄漏内存直到它退出。

queue:用于调度委托调用和完成处理程序的操作队列。 队列应该是一个串行队列,以确保回调的正确顺序。 如果为nil,会话将创建一个串行操作队列以执行所有委托方法调用和完成处理程序调用。

这里可以看到,创建session对象需要一个NSURLSessionConfiguration对象。(了解更多NSURLSessionConfiguration可以看我这篇文章)

2、属性及方法
// 创建session时的参数
@property (readonly, retain) NSOperationQueue *delegateQueue;
@property (nullable, readonly, retain) id <NSURLSessionDelegate> delegate;
@property (readonly, copy) NSURLSessionConfiguration *configuration;

// session描述性标签
@property (nullable, copy) NSString *sessionDescription;

/* 使会话无效,允许任何未完成的任务完成(有任务,继续任务)
 此方法立即返回,无需等待任务完成。 一旦会话失效,无法在会话中创建新任务,但现有任务会一直持续到完成。 在最后一个任务完成并且会话进行与这些任务相关的最后一个委托调用之后,会话将在其委托上调用URLSession:didBecomeInvalidWithError:方法,然后中断对委托和回调对象的引用。 无效后,会话对象不能重用。

在由sharedSession方法返回的会话上调用此方法不起作用。*/
- (void)finishTasksAndInvalidate;

/* 取消所有未完成的任务,然后使会话失效。(有任务,取消所有任务)
一旦失效,对委托和回调对象的引用就会被破坏。无效后,会话对象不能重用。

在由sharedSession方法返回的会话上调用此方法不起作用。
 */
- (void)invalidateAndCancel;

// 清空所有cookie,缓存和凭证存储,删除磁盘文件
- (void)resetWithCompletionHandler:(void (^)(void))completionHandler;   
// 刷新磁盘存储并清除瞬态网络缓存
- (void)flushWithCompletionHandler:(void (^)(void))completionHandler;   

// 在会话中异步完成回调包括未完成的所有数据,上传和下载任务。
- (void)getTasksWithCompletionHandler:(void (^)(NSArray<NSURLSessionDataTask *> *dataTasks, NSArray<NSURLSessionUploadTask *> *uploadTasks, NSArray<NSURLSessionDownloadTask *> *downloadTasks))completionHandler; 

// 所有任务
- (void)getAllTasksWithCompletionHandler:(void (^)(NSArray<__kindof NSURLSessionTask *> *tasks))completionHandler API_AVAILABLE(macos(10.11), ios(9.0), watchos(2.0), tvos(9.0)); 

// 各种task
// 请求任务。NSURLRequest 对象 (如URL,缓存策略,请求类型以及主体数据或主体流)
- (NSURLSessionDataTask *)dataTaskWithRequest:(NSURLRequest *)request;
// 请求任务。url 配合configuration 使用
- (NSURLSessionDataTask *)dataTaskWithURL:(NSURL *)url;

// 上传任务 fileURL:文件url
- (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)request fromFile:(NSURL *)fileURL;
// 上传任务 bodyData:数据
- (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)request fromData:(NSData *)bodyData;
// 上传任务 主体流
- (NSURLSessionUploadTask *)uploadTaskWithStreamedRequest:(NSURLRequest *)request;
// 下载任务
- (NSURLSessionDownloadTask *)downloadTaskWithRequest:(NSURLRequest *)request;
- (NSURLSessionDownloadTask *)downloadTaskWithURL:(NSURL *)url;
// 断点下载
- (NSURLSessionDownloadTask *)downloadTaskWithResumeData:(NSData *)resumeData;

// 建立到指定主机名和端口的双向TCP / IP连接
- (NSURLSessionStreamTask *)streamTaskWithHostName:(NSString *)hostname port:(NSInteger)port API_AVAILABLE(macos(10.11), ios(9.0), tvos(9.0)) __WATCHOS_PROHIBITED;
// 使用指定网络服务建立双向TCP / IP连接的任务。
- (NSURLSessionStreamTask *)streamTaskWithNetService:(NSNetService *)service API_AVAILABLE(macos(10.11), ios(9.0), tvos(9.0)) __WATCHOS_PROHIBITED;

// completionHandler处理
- (NSURLSessionDataTask *)dataTaskWithRequest:(NSURLRequest *)request completionHandler:(void (^)(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error))completionHandler;
- (NSURLSessionDataTask *)dataTaskWithURL:(NSURL *)url completionHandler:(void (^)(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error))completionHandler;

- (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)request fromFile:(NSURL *)fileURL completionHandler:(void (^)(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error))completionHandler;
- (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)request fromData:(nullable NSData *)bodyData completionHandler:(void (^)(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error))completionHandler;

- (NSURLSessionDownloadTask *)downloadTaskWithRequest:(NSURLRequest *)request completionHandler:(void (^)(NSURL * _Nullable location, NSURLResponse * _Nullable response, NSError * _Nullable error))completionHandler;
- (NSURLSessionDownloadTask *)downloadTaskWithURL:(NSURL *)url completionHandler:(void (^)(NSURL * _Nullable location, NSURLResponse * _Nullable response, NSError * _Nullable error))completionHandler;
- (NSURLSessionDownloadTask *)downloadTaskWithResumeData:(NSData *)resumeData completionHandler:(void (^)(NSURL * _Nullable location, NSURLResponse * _Nullable response, NSError * _Nullable error))completionHandler;

3、NSURLSessionTask相关API
@interface NSURLSessionTask : NSObject <NSCopying, NSProgressReporting>
// 标识符 此值仅在单个会话的上下文中是唯一的; 其他会话中的任务可能具有相同的taskIdentifier值。
@property (readonly)                 NSUInteger    taskIdentifier;    
// 
@property (nullable, readonly, copy) NSURLRequest  *originalRequest;  /* may be nil if this is a stream task */
@property (nullable, readonly, copy) NSURLRequest  *currentRequest;   /* may differ from originalRequest due to http server redirection */
// 服务器对当前活动请求的响应
@property (nullable, readonly, copy) NSURLResponse *response;         /* may be nil if no response has been received */

// 整体任务进度
@property (readonly, strong) NSProgress *progress API_AVAILABLE(macos(10.13), ios(11.0), watchos(4.0), tvos(11.0));

/*  网络负载应该开始的最早日期
对于从后台NSURLSession实例创建的任务,此属性表示网络负载不应该在此日期之前开始。 设置此属性并不能保证加载将从指定的日期开始,而只是它不会马上开始。 如果未指定,则不使用启动延迟。
此属性对从非后台会话创建的任务没有影响。*/
@property (nullable, copy) NSDate *earliestBeginDate API_AVAILABLE(macos(10.13), ios(11.0), watchos(4.0), tvos(11.0));

/* 客户期望发送的字节数的期待上限。
为此属性设置的值应考虑HTTP头和正文数据或正文流的大小。如果未指定值,则系统将使用NSURLSessionTransferSizeUnknown。该属性由系统用来优化URL会话任务的调度。强烈建议开发人员尽可能提供近似的上限或确切的字节数,而不是接受默认值。 */
@property int64_t countOfBytesClientExpectsToSend API_AVAILABLE(macos(10.13), ios(11.0), watchos(4.0), tvos(11.0));

/* 客户期望接收的字节数的期待上限。
为此属性设置的值应考虑HTTP响应头和响应主体的大小。如果未指定值,则系统将使用NSURLSessionTransferSizeUnknown。该属性由系统用来优化URL会话任务的调度。强烈建议开发人员尽可能提供近似的上限或确切的字节数,而不是接受默认值。 */
@property int64_t countOfBytesClientExpectsToReceive API_AVAILABLE(macos(10.13), ios(11.0), watchos(4.0), tvos(11.0));

// 实际发送和接受的字节
@property (readonly) int64_t countOfBytesReceived;
@property (readonly) int64_t countOfBytesSent;

@property (readonly) int64_t countOfBytesExpectedToSend;
@property (readonly) int64_t countOfBytesExpectedToReceive;

@property (nullable, copy) NSString *taskDescription;

// 将任务标记为取消
- (void)cancel;
// 暂停
- (void)suspend;
// 恢复任务
- (void)resume;

// 状态
@property (readonly) NSURLSessionTaskState state;

@property (nullable, readonly, copy) NSError *error;

/* 优先级 范围在0~1 默认0.5 */
@property float priority API_AVAILABLE(macos(10.10), ios(8.0), watchos(2.0), tvos(9.0));

@end

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 */
4、NSURLSessionTask子类相关API

NSURLSessionDataTask、NSURLSessionUploadTask没有子类api

NSURLSessionDownloadTask:

/* 取消下载并回调(恢复数据以供以后使用)。 
只有满足以下条件时才能恢复下载:
1、请求资源后,资源并未发生变化
2、该任务是一个HTTP或HTTPS GET请求
3、服务器在其响应中提供ETag或Last-Modified标头(或两者都有)
4、服务器支持字节范围请求
5、系统为响应磁盘空间压力而未删除临时文件*/
- (void)cancelByProducingResumeData:(void (^)(NSData * _Nullable resumeData))completionHandler;

NSURLSessionStreamTask:

/*   异步地从流中读取若干个字节,并在完成时调用处理程序。
读取minBytes或最多maxBytes字节,并在会话委托队列中调用数据或错误的完成处理程序。如果发生错误,任何未完成的读取也将失败,并且新的读取请求将立即出错。*/
- (void)readDataOfMinLength:(NSUInteger)minBytes maxLength:(NSUInteger)maxBytes timeout:(NSTimeInterval)timeout completionHandler:(void (^) (NSData * _Nullable data, BOOL atEOF, NSError * _Nullable error))completionHandler;

// 将指定的数据异步写入流,并在完成时调用处理程序。
- (void)writeData:(NSData *)data timeout:(NSTimeInterval)timeout completionHandler:(void (^) (NSError * _Nullable error))completionHandler;

/*获取流 
完成所有已排队的读取和写入,然后调用URLSession:streamTask:didBecomeInputStream:outputStream:delegate消息。 收到该消息时,任务对象被视为已完成,并且不会再收到任何委托消息。*/ */
- (void)captureStreams;

/* 排队请求以关闭底层套接字的写入结束。 所有未完成的IO将在套接字的写入端关闭之前完成。 但是,服务器可能会继续将字节写回到客户端,因此最佳做法是从服务器继续读取,直到你收到EOF。 */
- (void)closeWrite;

/* 排队请求以关闭底层套接字的读取端。 所有未完成的IO将在读取端关闭之前完成。 你可以继续写入服务器。 */
- (void)closeRead;

/* 开始加密握手。 握手在所有待处理IO完成后开始。 TLS认证回调被发送到会话-URLSession:task:didReceiveChallenge:completionHandler: */
- (void)startSecureConnection;

// 
完成所有挂起的安全IO后,干净地关闭安全连接。
- (void)stopSecureConnection;
5、NSURLSessionDelegate
/* 通知URL会话该会话已失效。
如果通过调用finishTasksAndInvalidate方法使会话失效,则会话将一直等待,直到会话中的最终任务完成或失败,然后再调用此委托方法。如果您调用invalidateAndCancel方法,会话将立即调用此委托方法。 */
- (void)URLSession:(NSURLSession *)session didBecomeInvalidWithError:(nullable NSError *)error;

/* 响应来自远程服务器的会话级别认证请求,从代理请求凭据。
这种方法在两种情况下被调用:
1、远程服务器请求客户端证书或Windows NT LAN Manager(NTLM)身份验证时,允许您的应用程序提供适当的凭据
2、当会话首先建立与使用SSL或TLS的远程服务器的连接时,允许您的应用程序验证服务器的证书链
如果您未实现此方法,则会话会调用其委托的URLSession:task:didReceiveChallenge:completionHandler:方法。
注:此方法仅处理NSURLAuthenticationMethodNTLM,NSURLAuthenticationMethodNegotiate,NSURLAuthenticationMethodClientCertificate和NSURLAuthenticationMethodServerTrust身份验证类型。对于所有其他认证方案,会话仅调用URLSession:task:didReceiveChallenge:completionHandler:方法。 */
- (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
                                             completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * _Nullable credential))completionHandler;

/* 告诉委托所有session里的消息都已发送。 */
- (void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session API_AVAILABLE(ios(7.0), watchos(2.0), tvos(9.0)) API_UNAVAILABLE(macos);
6、NSURLSessionTaskDelegate
/* 告诉代理现在将开始加载延迟的URL会话任务。
当具有延迟开始时间的后台会话任务(由earliestBeginDate属性设置)准备就绪时,将调用此方法。只有在等待网络负载时请求可能变陈旧并需要被新请求替换时,才应实现此委托方法。
为了继续加载,委托人必须调用完成处理程序,并传递一个处理方式来指示任务应该如何进行。传递NSURLSessionDelayedRequestCancel处置等效于直接调用任务的取消。 */
- (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));

/* 告诉代理,在开始网络加载之前,任务正在等待,直到合适的连接可用。
如果NSURLSessionConfiguration的waitsForConnectivity属性为true并且没有足够的连接,则调用此方法。 代表可以利用这个机会来更新用户界面; 例如通过呈现离线模式或仅限蜂窝模式。
此方法最多只能在每个任务中调用一次,并且仅在连接最初不可用时调用。 它永远不会被调用后台会话,因为这些会话会忽略waitsForConnectivity。
 */
- (void)URLSession:(NSURLSession *)session taskIsWaitingForConnectivity:(NSURLSessionTask *)task
    API_AVAILABLE(macos(10.13), ios(11.0), watchos(4.0), tvos(11.0));

/* 告诉委托远程服务器请求HTTP重定向。
此方法仅适用于默认和临时会话中的任务。 后台会话中的任务会自动遵循重定向。 */
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
                     willPerformHTTPRedirection:(NSHTTPURLResponse *)response
                                     newRequest:(NSURLRequest *)request
                              completionHandler:(void (^)(NSURLRequest * _Nullable))completionHandler;

/* 响应来自远程服务器的认证请求,从代理请求凭证。
 该方法处理任务级别的身份验证挑战。 NSURLSessionDelegate协议还提供了会话级别的身份验证委托方法。所调用的方法取决于身份验证挑战的类型:
对于会话级挑战-NSURLAuthenticationMethodNTLM,NSURLAuthenticationMethodNegotiate,NSURLAuthenticationMethodClientCertificate或NSURLAuthenticationMethodServerTrust - NSURLSession对象调用会话委托的URLSession:didReceiveChallenge:completionHandler:方法。如果您的应用程序未提供会话委托方法,则NSURLSession对象会调用任务委托人的URLSession:task:didReceiveChallenge:completionHandler:方法来处理该挑战。
对于非会话级挑战(所有其他挑战),NSURLSession对象调用会话委托的URLSession:task:didReceiveChallenge:completionHandler:方法来处理挑战。如果您的应用程序提供会话委托,并且您需要处理身份验证,那么您必须在任务级别处理身份验证,或者提供明确调用每会话处理程序的任务级别处理程序。会话委托的URLSession:didReceiveChallenge:completionHandler:方法不针对非会话级别的挑战进行调用。*/
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
                            didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge 
                              completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * _Nullable credential))completionHandler;

/* 当任务需要新的请求主体流发送到远程服务器时,告诉委托。
这种委托方法在两种情况下被调用:
1、如果使用uploadTaskWithStreamedRequest创建任务,则提供初始请求正文流:
2、如果任务因身份验证质询或其他可恢复的服务器错误需要重新发送包含正文流的请求,则提供替换请求正文流。
注:如果代码使用文件URL或NSData对象提供请求主体,则不需要实现此功能。 */
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
                              needNewBodyStream:(void (^)(NSInputStream * _Nullable bodyStream))completionHandler;

/* 定期通知代理向服务器发送主体内容的进度。(上传进度) */
- (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));

// 告诉代理该任务完成传输数据。
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
                           didCompleteWithError:(nullable NSError *)error;
7、NSURLSessionDataDelegate<NSURLSessionTaskDelegate>
/* 告诉代理数据任务从服务器收到初始回复(headers)。
NSURLSessionResponseDisposition枚举:
NSURLSessionResponseCancel = 0,                                      /* 取消加载, 与[task cancel]一致 */
NSURLSessionResponseAllow = 1,                                       /* 继续加载 */
NSURLSessionResponseBecomeDownload = 2,                              /* 转为下载 */
NSURLSessionResponseBecomeStream API_AVAILABLE(macos(10.11), ios(9.0), watchos(2.0), tvos(9.0)) = 3,  /* 转为流任务*/ 
*/
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask
                                 didReceiveResponse:(NSURLResponse *)response
                                  completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler;

/* 告诉代理数据任务已更改为下载任务。
当委托的URLSession:dataTask:didReceiveResponse:completionHandler:方法决定将数据请求的处置更改为下载时,会话将调用此委托方法为你提供新的下载任务。 在此调用之后,会话委托不会收到与原始数据任务相关的其他委托方法调用。 */
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask
                              didBecomeDownloadTask:(NSURLSessionDownloadTask *)downloadTask;

/* 告诉委托数据任务已更改为流任务
当委托的URLSession:dataTask:didReceiveResponse:completionHandler:方法决定将处置从数据请求更改为流时,会话将调用此委托方法为你提供新的流任务。 在此调用之后,会话委托不会收到与原始数据任务相关的其他委托方法调用。

对于pipelined的请求,流任务将只允许读取,并且对象将立即发送委托消息URLSession:writeClosedForStreamTask :. 通过在其NSURLSessionConfiguration对象上设置HTTPShouldUsePipelining属性,或通过在NSURLRequest对象上设置HTTPShouldUsePipelining属性来为各个请求设置会话中的所有请求,可以禁用管道传输。 */
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask
                                didBecomeStreamTask:(NSURLSessionStreamTask *)streamTask;

/* 告诉代理该数据任务已经收到了一些预期的数据。 
由于NSData对象通常是由许多不同的数据对象拼凑而成的,因此尽可能使用NSData的enumerateByteRangesUsingBlock:方法遍历数据,而不是使用bytes方法(将NSData对象平化为单个内存块)。
此委托方法可能被多次调用,并且每次调用仅提供自上次调用后收到的数据。 如果需要,该应用负责积累这些数据。*/
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask
                                     didReceiveData:(NSData *)data;

/* 询问委托数据(或上传)任务是否应将响应存储在缓存中。
会话在任务完成接收所有预期数据后调用此委托方法。如果未实现此方法,则默认行为是使用会话配置对象中指定的缓存策略。此方法的主要目的是防止特定URL的缓存或修改与URL响应关联的userInfo字典。
只有在处理请求的NSURLProtocol决定缓存响应时才调用此方法。通常,只有满足以下所有条件时才会缓存响应:
1、请求是针对HTTP或HTTPS URL(或你自己的支持缓存的自定义网络协议)。
2、请求成功(状态码在200-299范围内)。
3、提供的响应来自服务器,而不是缓存。
4、会话配置的缓存策略允许缓存。
5、提供的NSURLRequest对象的缓存策略(如果适用)允许缓存。
6、服务器响应中的缓存相关头(如果存在)允许缓存。
7、响应大小足够小,可以合理地放入缓存中。 (例如,如果您提供磁盘缓存,则响应不得超过磁盘缓存大小的5%。)
注:如果委托实现此方法,则它必须调用completionHandler完成处理程序;否则,应用程序会泄漏内存。
 */
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask
                                  willCacheResponse:(NSCachedURLResponse *)proposedResponse 
                                  completionHandler:(void (^)(NSCachedURLResponse * _Nullable cachedResponse))completionHandler;
8、NSURLSessionDownloadDelegate <NSURLSessionTaskDelegate>
/* 告诉委托下载任务已完成下载。
location:
临时文件的文件URL。 由于该文件是临时文件,因此必须先打开文件进行阅读或将其移至应用程序的沙箱容器目录中的永久位置,然后才能从此委派方法返回。
如果选择打开文件进行阅读,则应该在另一个线程中进行实际阅读,以避免阻塞委托队列。 */
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask
                              didFinishDownloadingToURL:(NSURL *)location;

@optional
/* 定期通知代理有关下载的进度。 */
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask
                                           didWriteData:(int64_t)bytesWritten
                                      totalBytesWritten:(int64_t)totalBytesWritten
                              totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite;

/* 告诉委托下载任务已经恢复下载。
filrOffest:
如果文件的缓存策略或上次修改日期阻止重新使用现有内容,则该值为零。否则,该值是一个整数,表示磁盘上不需要再次检索的字节数。

如果可恢复的下载任务被取消或失败,可以请求resumeData对象,该对象将提供足够的信息以重新开始下载。稍后,你可以调用downloadTaskWithResumeData:或downloadTaskWithResumeData:completionHandler:使用该数据。
当你调用这些方法时,你会得到一个新的下载任务。只要恢复该任务,会话就会使用该新任务调用其委托的URLSession:downloadTask:didResumeAtOffset:expectedTotalBytes:方法,以指示恢复下载。 */
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask
                                      didResumeAtOffset:(int64_t)fileOffset
                                     expectedTotalBytes:(int64_t)expectedTotalBytes;
9、NSURLSessionStreamDelegate <NSURLSessionTaskDelegate>
@optional
/* 告诉委托底层套接字的读取面已经关闭。
即使当前过程没有读取,也可以调用此方法。 此方法并不表示流达到end-of-file(EOF),从而不能读取更多数据。 */
- (void)URLSession:(NSURLSession *)session readClosedForStreamTask:(NSURLSessionStreamTask *)streamTask;

/* 告诉委托底层套接字的写入端已关闭。 
即使当前过程没有写入,也可以调用此方法。*/
- (void)URLSession:(NSURLSession *)session writeClosedForStreamTask:(NSURLSessionStreamTask *)streamTask;

/* 告诉委托流已经检测到通往主机更好的路由。 */
- (void)URLSession:(NSURLSession *)session betterRouteDiscoveredForStreamTask:(NSURLSessionStreamTask *)streamTask;

/* 告诉委托,流任务已完成,由于流任务调用captureStreams方法。
此委托方法仅在流任务的所有入队读取和写入操作完成后才会调用。 */
- (void)URLSession:(NSURLSession *)session streamTask:(NSURLSessionStreamTask *)streamTask
                                 didBecomeInputStream:(NSInputStream *)inputStream
                                         outputStream:(NSOutputStream *)outputStream;
10、NSURLSessionTaskTransactionMetrics

NSURLSessionTaskTransactionMetrics对象封装了执行会话任务期间收集的性能指标。 每个对象由请求和响应属性组成,对应于相应任务的请求和响应。 它还包含时间指标,从fetchStartDate开始,以responseEndDate结尾,以及其他特征,如networkProtocolName和resourceFetchType。

URL会话任务的时间度量时间表

@property (copy, readonly) NSURLRequest *request;
//  如果发生错误并且没有生成响应,则可以为nil
@property (nullable, copy, readonly) NSURLResponse *response;

// 用户代理开始获取资源的时间,无论是否从服务器或本地资源中检索资源。
@property (nullable, copy, readonly) NSDate *fetchStartDate;
// 用户代理启动资源名称查找之前的时间。
@property (nullable, copy, readonly) NSDate *domainLookupStartDate;
// 名称查询完成后的时间。
@property (nullable, copy, readonly) NSDate *domainLookupEndDate;
// 用户代理开始建立到服务器的连接之前的时间。
@property (nullable, copy, readonly) NSDate *connectStartDate;

//如果使用加密连接,则secureConnectionStartDate是用户代理刚刚开始安全握手以保护当前连接之前的时间。如果未使用加密连接,则此属性设置为零。
@property (nullable, copy, readonly) NSDate *secureConnectionStartDate;
//如果使用加密连接,则secureConnectionEndDate是安全握手完成后的时间。如果未使用加密连接,则此属性设置为零。
@property (nullable, copy, readonly) NSDate *secureConnectionEndDate;
// 用户代理完成与服务器建立连接后的时间,包括完成与安全相关的握手和其他握手。
@property (nullable, copy, readonly) NSDate *connectEndDate;
//用户代理开始请求源之前的时间,无论是从服务器还是从本地资源中检索资源。
@property (nullable, copy, readonly) NSDate *requestStartDate;
// 用户代理完成请求源后的时间,无论资源是从服务器还是从本地资源中检索。
@property (nullable, copy, readonly) NSDate *requestEndDate;
//用户代理刚收到服务器或本地资源响应的第一个字节后的时间。
@property (nullable, copy, readonly) NSDate *responseStartDate;
//用户代理收到资源的最后一个字节后的时间。
@property (nullable, copy, readonly) NSDate *responseEndDate;

/* 用于获取资源的网络协议,由ALPN协议ID标识序列[RFC7301]标识。
如果配置了代理并建立了隧道连接,则此属性将返回隧道协议的值。 */
@property (nullable, copy, readonly) NSString *networkProtocolName;
// 如果使用代理连接来获取资源,则此属性设置为YES。
@property (assign, readonly, getter=isProxyConnection) BOOL proxyConnection;
// 如果使用持续连接来获取资源,则此属性设置为YES。
@property (assign, readonly, getter=isReusedConnection) BOOL reusedConnection;
// 指示资源是否已从本地缓存中加载,推送或检索。
@property (assign, readonly) NSURLSessionTaskMetricsResourceFetchType resourceFetchType;

-(instancetype)init;
11、NSURLSessionTaskMetrics

NSURLSessionTaskMetrics对象封装了会话任务的度量标准。 每个对象都包含taskInterval和redirectCount以及执行任务期间所做的每个请求/响应事务的指标。

// 包含为在任务执行期间创建的每个请求/响应事务收集的度量标准。
@property (copy, readonly) NSArray<NSURLSessionTaskTransactionMetrics *> *transactionMetrics;
// 从任务创建时间到任务完成时间的时间间隔。
@property (copy, readonly) NSDateInterval *taskInterval;
// 记录的重定向的数量。
@property (assign, readonly) NSUInteger redirectCount;

-(instancetype)init;

推荐阅读更多精彩内容