附录A:URL会话的生命周期

2017-02-14  本文已影响0人  现在立刻马上zzz

URL会话的生命周期(Life Cycle of a URL Session)

您可以通过两种方式使用NSURLSessionAPI:使用系统提供的代理或使用您自己的代理。一般来说,如果您的应用程序执行以下任何操作,您必须使用自己的代理:

如果您的应用程序不需要执行任何这些操作,您的应用程序可以使用系统提供的代理。根据您选择的技术,您应该阅读以下部分之一:

具有系统提供的代理的URL会话的生命周期(Life Cycle of a URL Session with System-Provided Delegates)

如果您使用NSURLSession类而不提供代理对象,则系统提供的代理会处理您的许多详细信息。以下是当您使用NSURLSession和系统提供的代理时,您的应用程序必须进行的方法调用和完成处理程序(completion handler)调用的基本顺序:

  1. 创建会话配置。对于后台会话,此配置必须包含唯一标识符。存储该标识符,如果您的应用程序崩溃或已终止或暂停(suspended),则使用该标识符与会话重新关联。

  2. 创建一个会话,指定一个配置对象和一个nil代理。

  3. 在会话中创建每个都表示资源请求的任务对象。

每个任务从暂停(suspended)状态开始。在您的应用程序调用恢复(resume)任务后,它开始下载指定的资源。

任务对象是NSURLSessionTask的子类-NSURLSessionDataTaskNSURLSessionUploadTaskNSURLSessionDownloadTask,具体取决于您尝试实现的行为。

虽然您的应用程序可以(通常应该)向会话中添加多个任务,但是为了简单起见,剩余的步骤描述了单个任务的生命周期。

重要:如果您使用NSURLSession类而不提供代理,则您的应用程序必须使用接受completionHandler参数的调用创建任务,否则无法从类中获取数据。

  1. 对于下载任务,在从服务器传输期间,如果用户通知您的应用程序暂停下载,请通过调用cancelByProducingResumeData:方法来取消该任务。稍后,将返回的恢复数据传递给downloadTaskWithResumeData:downloadTaskWithResumeData:completionHandler:方法,以创建一个新的下载任务,继续下载。

  2. 当任务完成时,NSURLSession对象调用任务的完成处理程序(completion handler)。

注意:NSURLSession不通过error参数报告服务器错误。您的应用通过error参数接收的唯一错误是客户端错误,例如无法解析主机名或连接到主机。错误代码在URL加载系统错误代码(URL Loading System Error Codes)中描述。

服务器端错误通过NSHTTPURLResponse对象中的HTTP状态代码报告。有关更多信息,请阅读NSHTTPURLResponseNSURLResponse类的文档。

  1. 当您的应用程序不再需要会话时,通过调用invalidateAndCancel(取消未完成的任务)或finishTasksAndInvalidate(允许未完成的任务完成,然后使对象失效)使其失效。

具有自定义代理的URL会话的生命周期(Life Cycle of a URL Session with Custom Delegates)

您可以经常使用NSURLSessionAPI无需提供代理。但是,如果您使用NSURLSessionAPI进行后台下载和上传,或者如果需要以非默认方式处理身份验证或缓存,则必须提供符合「会话代理协议,一个或多个任务代理协议或这些协议的某些组合」的代理。这个代理有很多用途:

如果您使用自定义代理,则URL会话的完整生命周期更复杂。以下是应用程序必须的方法和使用具有自定义代理的NSURLSession时应用程序接收的代理调用的基本顺序:

  1. 创建会话配置。对于后台会话,此配置必须包含唯一标识符。存储该标识符,如果您的应用程序崩溃或已终止或暂停,则使用该标识符与会话重新关联。

  2. 创建会话,指定配置对象和可选的代理。

  3. 在会话中创建每个都表示资源请求的任务对象。

每个任务从暂停(suspended)状态开始。在您的应用程序调用恢复(resume)任务后,它开始下载指定的资源。

任务对象是NSURLSessionTask的子类-NSURLSessionDataTaskNSURLSessionUploadTaskNSURLSessionDownloadTask,具体取决于您尝试实现的行为。

虽然您的应用程序可以(通常应该)向会话中添加多个任务,但是为了简单起见,剩余的步骤描述了单个任务的生命周期。

  1. 如果远程服务器返回指示需要身份验证的状态代码,并且如果该身份验证需要连接级别质询(例如SSL客户端证书),则NSURLSession将调用认证质询代理方法。

注意:Kerberos身份验证是透明处理的。

如果上传任务的身份验证失败,那么如果任务的数据是从流提供的,NSURLSession对象将调用代理的URLSession:task:needNewBodyStream:代理方法。然后,代理必须提供一个新的NSInputStream对象,以提供新请求的主体数据。

有关为NSURLSession编写身份验证代理方法的详细信息,请阅读身份验证质询和TLS链验证(Authentication Challenges and TLS Chain Validation)

  1. 收到HTTP重定向响应时,NSURLSession对象调用代理的URLSession:task:willPerformHTTPRedirection:newRequest:completionHandler:方法。该代理方法使用提供的NSURLRequest对象(遵循重定向)调用提供的完成处理程序,新的NSURLRequest对象(重定向到其他网址)或nil(将重定向的响应主体视为有效响应并将其作为结果返回)。
  1. 对于通过调用downloadTaskWithResumeData:downloadTaskWithResumeData:completionHandler:创建的(重新)下载任务,NSURLSession调用代理的URLSession:downloadTask:didResumeAtOffset:expectedTotalBytes:方法,新的任务对象作为参数。

  2. 对于数据任务,NSURLSession对象调用代理的URLSession:dataTask:didReceiveResponse:completionHandler:方法。决定是否将数据任务转换为下载任务,然后调用完成回调以继续接收数据或下载数据。

如果您的应用程序选择将数据任务转换为下载任务,NSURLSession会调用代理的URLSession:dataTask:didBecomeDownloadTask:方法,并将新的下载任务作为参数。在此调用之后,代理不从数据任务接收进一步的回调,并开始从下载任务接收回调。

  1. 如果任务是使用uploadTaskWithStreamedRequest:创建的,那么NSURLSession会调用代理的URLSession:task:needNewBodyStream:方法来提供主体数据。

  2. 在将主体内容初始上传到服务器(如果适用)期间,代理定期接收URLSession:task:didSendBodyData:totalBytesSent:totalBytesExpectedToSend:报告上传进度的回调。

  3. 在从服务器传输期间,任务代理定期接收回调以报告传输进度。对于下载任务,会话调用代理的URLSession:downloadTask:didWriteData:totalBytesWritten:totalBytesExpectedToWrite:方法,字节数已成功写入磁盘。对于数据任务,会话在接收到实际的数据片段时调用代理的URLSession:dataTask:didReceiveData:方法。

对于下载任务,在从服务器传输期间,如果用户告诉您的应用程序暂停下载,请通过调用cancelByProducingResumeData:方法来取消该任务。

稍后,如果用户要求您的应用程序恢复下载,请将返回的恢复数据传递给downloadTaskWithResumeData:downloadTaskWithResumeData:completionHandler:方法以创建一个继续下载的新下载任务,然后转到步骤3(创建和恢复任务 对象)。

  1. 对于数据任务,NSURLSession对象调用代理的URLSession:dataTask:willCacheResponse:completionHandler:方法。您的应用程序应该决定是否允许缓存。如果不实现此方法,则默认行为是使用会话配置对象中指定的缓存策略。

  2. 如果下载任务成功完成,则NSURLSession对象调用任务的URLSession:downloadTask:didFinishDownloadingToURL:方法,其中包含临时文件的位置。在此代理方法返回之前,您的应用程序必须读取此文件中的响应数据或将其移动到应用程序沙盒容器目录中的永久位置。

  3. 当任何任务完成时,NSURLSession对象调用代理的URLSession:task:didCompleteWithError:方法,一个错误对象或nil(如果任务成功完成)作为参数。

如果任务失败,大多数应用程序应重试请求,直到用户取消下载或服务器返回一个错误,指示该请求永远不会成功。不过,您的应用程式不应立即重试。相反,它应该使用可达性(reachability)API来确定服务器是否可达,并且只有当它接收到可达性已更改的通知时才应该发出新请求。

如果可以恢复下载任务,NSError对象的userInfo字典包含NSURLSessionDownloadTaskResumeData键的值。您的应用程序应该传递此值以调用downloadTaskWithResumeData:downloadTaskWithResumeData:completionHandler:创建一个新的下载任务,继续现有的下载。

如果无法恢复任务,您的应用程序应创建一个新的下载任务,并从头重新启动事务。

在任一情况下,如果由于服务器错误以外的任何原因传输失败,请转到步骤3(创建和恢复任务对象)。

注意:NSURLSession不通过error参数报告服务器错误。代理通过error参数接收的唯一错误是客户端错误,例如无法解析主机名或连接到主机。错误代码在URL加载系统错误代码中描述。

服务器端错误通过NSHTTPURLResponse对象中的HTTP状态代码报告。

有关更多信息,请阅读NSHTTPURLResponseNSURLResponse类的文档。

  1. 如果响应是多部分编码的,则会话可以再次调用代理的didReceiveResponse方法,然后再执行零个或多个额外的didReceiveData调用。如果发生这种情况,请转到步骤7(处理didReceiveResponse调用)。

  2. 当您不再需要会话时,通过调用invalidateAndCancel(取消未完成的任务)或finishTasksAndInvalidate(允许未完成的任务完成,然后使对象失效)使其无效。

在使会话无效后,当所有未完成的任务已被取消或已完成时,会话向代理发送URLSession:didBecomeInvalidWithError:消息。

当该代理方法返回时,会话将其强引用返回给代理(释放对代理的强引用)。

要点:会话对象保持对代理的强引用,直到应用程序显式使会话无效。如果你不使会话无效,你的应用程序泄漏内存。

如果您的应用程序取消正在进行的下载,NSURLSession对象将调用代理的URLSession:task:didCompleteWithError:方法,就像发生错误一样。

上一篇 下一篇

猜你喜欢

热点阅读