NSURLSession的代理
NSURLSession API提供了四种协议,可以定义您的应用程序可以实现的委托方法,以便对会话和任务行为提供更细粒度的控制。
NSURLSessionDelegate
NSURLSessionDelegate协议描述NSURLSession对象调用其委托来处理会话级事件的方法。 除了本协议中定义的方法之外,大多数代理还应该实现NSURLSessionTaskDelegate,NSURLSessionDataDelegate和NSURLSessionDownloadDelegate协议中的一些或所有方法来处理任务级事件。
Overview
NSURLSession对象不一定需要一个代理。 如果未分配代理,则使用系统提供的代理,同时你必须提供completion的回调以获取数据。
Symbols
Delegate Methods
1. - (void)URLSession:(NSURLSession *)session didBecomeInvalidWithError:(NSError *)error
告知session已经无效;
session:无效的那个会话;
error:导致会话失效的错误,如果是显示无效的,则为nil;
如果通过调用其finishTasksAndInvalidate方法使会话无效,那么在调用此委托方法之前,会话将等待直到会话中的最后一个任务完成或失败。 如果调用invalidateAndCancel方法,则会话立即调用该委托方法。
2. - (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler
对服务器的会话级认证请求做出响应;
session: 包含需要身份认证的任务的session
challenge:包含证书的对象。
completionHandler:托方法必须调用的回调。 其参数如下:
a. disposition:描述如何处理认证的几个常量之一
b. credential:如果disposition为NSURLSessionAuthChallengeUseCredential则表示需要认证的证书,否则为NULL
这种方法在以下两种情况下被调用:
a. 当服务器要求提供客户端证书或Windows NT LAN Manager(NTLM)身份验证时,允许应用程序提供适当的凭据;
b. 当会话第一次使用SSL或TLS与服务器建立连接时,允许应用验证服务器的证书链;
如果不实现此方法,会话将调用其代理的URLSession:task:didReceiveChallenge:completionHandler:方法。
NOTE:此方法仅处理NSURLAuthenticationMethodNTLM,NSURLAuthenticationMethodNegotiate,NSURLAuthenticationMethodClientCertificate和NSURLAuthenticationMethodServerTrust身份验证类型。 对于所有其他身份验证方案,会话仅调用URLSession:task:didReceiveChallenge:completionHandler:方法;
3. - (void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session;
告诉代理session的队列里所有的任务都已经完成;
session: 不再有任何未完成请求的session。
在iOS中,当后台传输完成或需要认证时,如果应用没有运行,则应用程序将在后台自动重新启动,并且应用的UIApplicationDelegate将发送application:handleEventsForBackgroundURLSession:completionHandler:消息。 这个调用包含导致应用重启的session的id。 我们的应该在创建具有相同标识符的后台配置对象之前存储该completionHandler,并使用该配置创建新的session。 新创建的会话将自动重新与正在进行的后台活动相关联。
当应用稍后收到一个URLSessionDidFinishEventsForBackgroundURLSession:消息时,这表示先前为此会话队列的所有消息已经交付,现在可以安全地调用先前存储的completionHandler或开始可能导致调用完成的任何内部更的回调。
Important:
因为提供的completionHandler是UIKit的一部分,我们必须在主线程上调用它。 例如:
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
storedHandler();
}];
Constants
typedef enum NSURLSessionAuthChallengeDisposition : NSInteger {
NSURLSessionAuthChallengeUseCredential = 0,
NSURLSessionAuthChallengePerformDefaultHandling = 1,
NSURLSessionAuthChallengeCancelAuthenticationChallenge = 2,
NSURLSessionAuthChallengeRejectProtectionSpace = 3
} NSURLSessionAuthChallengeDisposition;
为了响应认证,session或者代理提供的一些常量;
1. NSURLSessionAuthChallengeUseCredential:使用指定的证书,可能为nil;
2. NSURLSessionAuthChallengePerformDefaultHandling:使用默认处理去做认证工作,就好像这个代理方法没有被实现一样。 提供的证书参数被忽略;
3. NSURLSessionAuthChallengeCancelAuthenticationChallenge:取消整个请求,提供的证书参数被忽略;
4. NSURLSessionAuthChallengeRejectProtectionSpace:拒绝此认证,并使用下一个身份验证保护空间再次调用身份验证代理方法。 提供的证书参数被忽略;
NSURLSessionTaskDelegate
NSURLSessionTaskDelegate协议定义了在使用任何类型的NSURLSession任务时应该实现的特定于任务的委托方法。
Overview
如果我们正在使用下载任务,还可以在NSURLSessionDownloadDelegate协议中实现方法。
如果我们正在使用数据或上传任务,还可以在NSURLSessionDataDelegate协议中实现这些方法。
NOTE:NSURLSession对象不一定需要一个代理。 如果未分配代理,则使用系统提供的代理,同时你必须提供completion的回调以获取数据。
Symbols
1. - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler
通过代理做服务器的认证工作(任务级别)
session:包含要去认证的请求的任务的session;
task:要去认证的请求的任务;
challenge:包含证书的对象;
completionHandler:托方法必须调用的回调。 其参数如下:
a. disposition:描述如何处理认证的几个常量之一
b. credential:如果disposition为NSURLSessionAuthChallengeUseCredential则表示需要认证的证书,否则为NULL
此方法处理任务级身份认证。 NSURLSessionDelegate协议还提供了一个会话级的认证委托方法。调用的方法取决于身份验证挑战的类型:,具体见NSURLSessionDelegate的第二个代理方法;
对于非session级别的认证(所有其他认证),NSURLSession调用其代理的此方法;如果我们提供了session一个代理并且我们需要处理认证工作,那么我们必须要么在任务级别处理认证,要么为每个session的回调提供一个明确的任务级别的handle;(不懂~~~)
2. - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didSendBodyData:(int64_t)bytesSent totalBytesSent:(int64_t)totalBytesSent totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend
定期向代理的此方法通知向服务器发送body内容的进度。
session:data task所在的session;
task:发送请求的task;
bytesSent;自上一次该代理方法被调用以来发送的字节数。
totalBytesSent:到目前为止发送的总的字节数;
totalBytesExpectedToSend:body的预期长度。 URL加载系统可以通过三种方式确定上传数据的长度:
a. 从作为上传主体提供的NSData对象的长度;
b. 从作为上传任务的上传body(不是下载任务)提供的磁盘上的文件的长度;
c. 从请求对象中的Content-Length,如果您明确设置它;
否则,如果我们提供了流或body数据对象,则该值为NSURLSessionTransferSizeUnknown(-1),否则为0(0);
3. - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task needNewBodyStream:(void (^)(NSInputStream *bodyStream))completionHandler
告诉代理何时这个任务需要一个新的请求body流来发送给服务器;
completionHandler:代理方法应该使用新的body流调用completionHandler。
这个代理方法在两种情况下被调用:
a. 在使用uploadTaskWithStreamedRequest创建任务时,提供初始请求body流:
b. 如果任务需要重新发送一个带有body的请求,则调用此方法来提供一个替换的请求的body流,因为身份认证或者是其他可恢复的服务器错误。
NOTE:如果使用文件URL或NSData对象提供请求body,则不需要实现此操作。
4. - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task willPerformHTTPRedirection:(NSHTTPURLResponse *)response newRequest:(NSURLRequest *)request completionHandler:(void (^)(NSURLRequest *))completionHandler;
告知代理远程服务器请求HTTP重定向。
task:请求需要重定向的任务;
response:包含服务器对原始请求的响应对象;
request:新地址重定向的request;
completionHandler:如果需要重定向,使用代理方法参数中的request作为block的参数,如果不需要重定向,则直接以NULL为block的参数;
此方法仅用于默认和临时会话中的任务。 后台会话中的任务自动跟踪重定向。
5. - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didFinishCollectingMetrics:(NSURLSessionTaskMetrics *)metrics
告诉代理,session完成了手机任务的指标(不懂~~~)
6. - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
告诉代理task已经完成了传输任务;
服务器错误不会通过错误参数报告。 代理通过错误参数收到的唯一错误是客户端错误,例如无法解析主机名或连接到主机。
NSURLSessionDataDelegate
Overview
NSURLSessionDataDelegate协议定义了NSURLSession对象的代理可以实现的方法来处理特定于数据任务和上传任务的任务级事件。 会话代理还应执行NSURLSessionTaskDelegate协议中的方法来处理所有任务类型通用的任务级事件,以及NSURLSessionDelegate协议中处理会话级事件的方法。
NOTE:NSURLSession对象不一定需要一个代理。 如果未分配代理,则使用系统提供的代理,同时你必须提供completion的回调以获取数据。
completionHandler和代理方法需要二选一,如果使用了completionHandler,则代理方法不会走;
Symbols
Delegate Methods
1. - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler
告知代理,task已经从服务器那边收到了初始的回复(或回复的头部信息);
response:接收响应的对象;
completionHandler:通过回调来继续传输工作;传递常量以指示传输是否应继续作为数据任务或应成为下载任务。
a. 如果传递NSURLSessionResponseAllow,则任务将继续正常运行。
b. 如果传递NSURLSessionResponseCancel,则该任务将被取消。
c. 如果传递NSURLSessionResponseBecomeDownload作为配置,则将调用代理的URLSession:dataTask:didBecomeDownloadTask:方法来为提供取代当前任务的新的下载任务。
此方法是可选的,除非我们需要支持(相对模糊的)multipart / x-mixed-replace content type。 使用该content-type,服务器发送一系列的部分数据,每个部分用于替换上一部分。 会话在每个部分开始的时候调用此方法,然后我们应该适当地显示,丢弃或以其他方式处理上一部分。
如果不实现此代理方法,则会话始终允许任务继续。
2. - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didBecomeDownloadTask:(NSURLSessionDownloadTask *)downloadTask
告诉代理data task 已经转为了下载任务;
downloadTask:用来替换data task的新的下载任务;
当代理的URLSession:dataTask:didReceiveResponse:completionHandler:method决定将处理从数据请求更改为下载时,会话将调用此代理方法提供新的下载任务。 在此调用之后,会话代理不会调用与原始数据任务相关的其他代理方法。
3. - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didBecomeStreamTask:(NSURLSessionStreamTask *)streamTask
告诉代理data task 已经转为了流任务;
streamTask:用来替换data task的新的流任务;
当代理的URLSession:dataTask:didReceiveResponse:completionHandler:方法决定将数据请求的配置更改为流任务时,会话将调用此代理方法为您提供新的流任务。 在此调用之后,会话代理不会接收与原始数据任务相关的其他代理方法调用。
对于管道流的请求,流任务只允许读取,并且对象将立即发送代理消息URLSession:writeClosedForStreamTask :。 可以通过在其NSURLSessionConfiguration对象上设置HTTPShouldUsePipelining属性或通过在NSURLRequest对象上设置HTTPShouldUsePipelining属性来为各个请求设置会话中的所有请求来禁用管道流。
4. - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data
告诉代理data任务已经收到了一些预期的数据。
data: 已经传输的data;
因为NSData对象经常由许多不同的数据对象拼接在一起,只要有可能,使用NSData的枚举BteteRangesUsingBlock:方法遍历数据,而不是使用bytes方法来获得data的长度(将NSData对象平坦化为单个内存块)。
该代理方法可以被多次调用,并且每此调用仅提供自上一次调用以来收到的数据。 如果需要累计的数据,需要我们自行拼接。
5. - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask willCacheResponse:(NSCachedURLResponse *)proposedResponse completionHandler:(void (^)(NSCachedURLResponse *cachedResponse))completionHandler
是否需要将data task 或者是上传任务的响应缓存起来;
proposedResponse: 默认的缓存行为。 此行为是基于当前的缓存策略和接收到的头部(如Pragma和Cache-Control)的值来确定的。
completionHandler: 我们必须调用此回调以提供原始响应,该响应的修改版本或传NULL以防止缓存响应数据。 如果代理实现此方法,则必须调用此completionHandler; 否则,应用程序会内存泄漏。
在任务完成接收到所有预期数据后,会话将调用此代理方法。如果不实现此方法,则默认行为是使用会话配置对象中指定的缓存策略。该方法的主要目的是防止缓存特定URL或修改与URL响应相关联的userInfo信息。
只有处理请求的NSURLProtocol决定缓存响应时,才调用此方法。一般来说,响应只有在以下所有情况都成立的时候才被缓存:
a. 该请求是针对HTTP或HTTPS URL(或自定义支持缓存的网络协议)。
b. 请求成功(状态代码在200-299范围内)。
c. 服务器提供的response没有超过缓存。
d. 会话配置的缓存策略允许缓存。
e. 提供的NSURLRequest对象的缓存策略(如果适用)允许缓存。
f. 服务器响应中的缓存相关头(如果存在)允许缓存。
g. 响应大小足够小以合理地适应缓存。 (例如,如果提供磁盘缓存,则响应不得大于磁盘缓存大小的约5%。)
Constants
typedef enum NSURLSessionResponseDisposition : NSInteger {
NSURLSessionResponseCancel = 0,
NSURLSessionResponseAllow = 1,
NSURLSessionResponseBecomeDownload = 2,
NSURLSessionResponseBecomeStream = 3
} NSURLSessionResponseDisposition;
NSURLSessionResponseCancel:取消加载数据,相当于调用该task的- (void)cancel方法;
NSURLSessionResponseAllow:允许加载操作继续;
NSURLSessionResponseBecomeDownload:把数据请求转为一个下载任务;
NSURLSessionResponseBecomeStream:把数据请求转为一个流任务;
NSURLSessionDownloadDelegate
Overview
NSURLSessionDownloadDelegate协议定义了在使用NSURLSession下载任务时应该实现的委托方法。 除了这些方法之外,请务必在NSURLSessionTaskDelegate和NSURLSessionDelegate协议中实现方法来分别处理所有任务类型和会话级事件通用的事件。
NOTE:NSURLSession对象不一定需要一个代理。 如果未分配代理,则使用系统提供的代理,同时你必须提供completion的回调以获取数据。
Symbols
1. - (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didResumeAtOffset:(int64_t)fileOffset expectedTotalBytes:(int64_t)expectedTotalBytes;
告诉代理下载任务已经开始恢复下载;
fileOffset:如果文件的缓存策略或最后修改日期阻止对现有内容的重用,那么该值为零。 否则,该值是一个整数,表示磁盘上不需要重新获取的字节数。在某些情况下,当前文件传输的恢复可能上一个传输结束要更早。
expectedTotalBytes:由Content-Length头提供的文件的预期长度。 如果未提供此标头,则值为NSURLSessionTransferSizeUnknown。
如果一个可恢复的下载任务被取消或失败,我们可以请求一个resumeData对象提供足够的信息来重新启动下载。 之后我们可以通过与该数据调用downloadTaskWithResumeData:或downloadTaskWithResumeData:completionHandler:方法。
当我们调用这些方法时,我们将得到一个新的下载任务。 一旦恢复该任务,会话将使用该新任务调用其代理的URLSession:downloadTask:didResumeAtOffset:expectedTotalBytes:方法与来表明下载被恢复。
2. - (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite
定期通知代理下载的进度。
bytesWritten:自上次调用此代理方法后传输的字节数。
totalBytesWritten:目前为止传输的字节数;
totalBytesExpectedToWrite:由Content-Length头提供的文件的预期长度。 如果未提供此标头,则值为NSURLSessionTransferSizeUnknown。
3. - (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location
告诉代理下载任务已经完成;
location:临时文件的文件URL。 因为该文件是临时的,所以我们必须在从该代理方法返回之前打开要读取的文件或将其移动到应用的沙盒目录中。
如果我们选择打开文件进行阅读,我们应该在另一个线程中进行读取操作,以避免阻止代理队列。
NSURLSessionStreamDelegate
Overview
NSURLSessionStreamDelegate协议定义了在使用NSURLSession流任务时应该实现的委托方法。 除了这些方法之外,请务必在NSURLSessionTaskDelegate和NSURLSessionDelegate协议中实现方法来分别处理所有任务类型和会话级事件通用的事件。
NOTE:NSURLSession对象不一定需要一个代理。 如果未分配代理,则使用系统提供的代理,同时你必须提供completion的回调以获取数据。
Symbols
1. - (void)URLSession:(NSURLSession *)session readClosedForStreamTask:(NSURLSessionStreamTask *)streamTask
告诉代理底层套接字的读取端已经关闭。
streamTask:关闭了读取的流任务;
即使当前没有读取正在进行,也可以调用此方法。 此方法并不表示该流到达文件末尾(EOF),这样就不会再读取更多的数据。
2. - (void)URLSession:(NSURLSession *)session writeClosedForStreamTask:(NSURLSessionStreamTask *)streamTask
告诉代理底层套接字的写入端已经关闭。
即使没有写入正在进行,也可以调用此方法。
3. - (void)URLSession:(NSURLSession *)session betterRouteDiscoveredForStreamTask:(NSURLSessionStreamTask *)streamTask
告诉代理已经检测对于数据流来说到主机更好的路由;
当URL加载系统确定到端点主机的更好路由可用时,将调用此方法。 例如,当Wi-Fi接口可用时,可以调用此方法。
我们应该考虑先完成待定工作并创建新的流任务,以便在可用时利用更好的路线。
4. - (void)URLSession:(NSURLSession *)session streamTask:(NSURLSessionStreamTask *)streamTask didBecomeInputStream:(NSInputStream *)inputStream outputStream:(NSOutputStream *)outputStream
由于流任务调用captureStreams方法,告诉代理流任务已经完成。
inputStream:创建的输入流。 此NSInputStream对象未打开。
outputStream:创建的输出流。 此NSOutputStream对象未打开。
只有在完成流任务的所有入队读取和写入之后,才会调用此代理方法。
网友评论