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

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

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

  • 在应用程式未执行时,使用后台会话下载或上传内容。
  • 执行自定义身份验证。
  • 执行自定义SSL证书验证。
  • 决定是将传输下载到磁盘还是基于服务器返回的MIME类型或其他类似条件显示。
  • 从主体流(而不是NSData对象)上传数据。
  • 以编程方式限制缓存。
  • 以编程方式限制HTTP重定向。

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

  • 具有系统提供的代理的URL会话的生命周期(Life Cycle of a URL Session with System-Provided Delegates)提供了一个轻量描述,您的代码如何创建和使用URL会话。即使您打算编写自己的代理,也应该阅读本部分,因为它可以让您全面了解代码必须做什么才能配置对象并使用它。
  • 具有自定义代理的URL会话的生命周期(Life Cycle of a URL Session with Custom Delegates)提供了URL会话操作中的每个步骤的完整描述。您应参考本节来帮助您了解会话如何与其代理进行交互。特别地,这说明了每个代理方法被调用的时机。

具有系统提供的代理的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进行后台下载和上传,或者如果需要以非默认方式处理身份验证或缓存,则必须提供符合「会话代理协议,一个或多个任务代理协议或这些协议的某些组合」的代理。这个代理有很多用途:

  • 与下载任务一起使用时,NSURLSession对象使用代理为应用程序提供文件URL,以便获取下载的数据。
  • 所有后台下载和上传都需要代理。这些代理必须提供NSURLSessionDownloadDelegate协议中的所有代理方法。
  • 代理可以处理某些身份验证质询(authentication challenges)。
  • 代理提供主体流,用于将基于流的数据上传到远程服务器。
  • 代理可以决定是否遵循HTTP重定向。
  • NSURLSession对象使用代理为应用程序提供每个传输的状态。数据任务代理接收初始调用,在其中您可以将请求转换为下载和随后的调用,提供从远程服务器到达的数据。
  • 代理是NSURLSession对象可以在传输完成时告诉您的应用程序的一种方式。

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

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

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

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

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

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

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

  1. 如果远程服务器返回指示需要身份验证的状态代码,并且如果该身份验证需要连接级别质询(例如SSL客户端证书),则NSURLSession将调用认证质询代理方法。
  • 对于会话级别质询(challenges) -NSURLAuthenticationMethodNTLMNSURLAuthenticationMethodNegotiateNSURLAuthenticationMethodClientCertificateNSURLAuthenticationMethodServerTrust-NSURLSession对象调用会话代理URLSession:didReceiveChallenge:completionHandler:方法。如果您的应用程序没有提供会话代理方法,NSURLSession对象将调用任务代理URLSession:task:didReceiveChallenge:completionHandler:方法来处理质询。

  • 对于非会话级质询(所有其他),NSURLSession对象调用任务代理的URLSession:task:didReceiveChallenge:completionHandler:方法来处理质询。如果您的应用程序提供了一个会话代理,并且您需要处理身份验证,那么您必须在任务级别处理身份验证,或者提供显式调用每会话(per-session)处理程序的任务级处理程序。会话代理的URLSession:didReceiveChallenge:completionHandler:方法不是为非会话级调用的。

注意: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(将重定向的响应主体视为有效响应并将其作为结果返回)。
  • 如果遵循重定向,请返回到步骤4(身份验证质询处理)。

  • 如果代理没有实现此方法,重定向会跟随到最大重定向数。

  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:方法,就像发生错误一样。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,544评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,430评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,764评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,193评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,216评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,182评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,063评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,917评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,329评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,543评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,722评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,425评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,019评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,671评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,825评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,729评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,614评论 2 353

推荐阅读更多精彩内容