在session中任务的行为取决于三件事:session的类型(由创建它的配置对象的类型决定),任务的类型,以及当任务创建时app是否处于前台

Session类型

NSURLSession API支持三种类型的session,具体的类型是由创建该session的配置对象类型决定:

  • 默认session和其他框架中URL下载的方法类似,它基于磁盘缓存,并且将证书存储在用户的keychain中;
  • 短暂性的session是不会存储任何数据到磁盘的。所有的缓存、证书存储等等都是保存到RAM中并且与该session相关联。因此,如果我们在app中初始化这种session的话,这些数据都是自动清除的;
  • 后台session除了使用单独的进程来处理数据传输之外和默认的session有点儿类似。后台session有一些条件限制,具体的会在后面讲到。

    ///NSURLSessionConfiguration
    @property (class, readonly, strong) NSURLSessionConfiguration defaultSessionConfiguration;
    @property (class, readonly, strong) NSURLSessionConfiguration ephemeralSessionConfiguration;
    (NSURLSessionConfiguration )backgroundSessionConfigurationWithIdentifier:(NSString )identifier
    /// Swift
    URLSessionConfiguration.default
    URLSessionConfiguration.ephemeral
    URLSessionConfiguration.background(withIdentifier: "")
    

任务类型

在session中,NSURLSession类支持3中类型的任务:数据任务(data tasks),下载任务(download tasks),上传任务(upload tasks)。

  • 数据任务在发送和接收数据时使用NSData对象。数据任务一般用于简短、经常和服务器交互的请求。数据任务可以在每块儿数据都接收到了之后一整块儿返回给我们,或者是所有数据通过completion的回调一次性把数据返回。
  • 下载任务以文件的形式取回数据,并且支持当程序不在运行的时候后台下载。
  • 上传任务以文件的形式发送数据,同样也支持在程序没有运行的情况下后台上传。
NSURLSessionUploadTask
NSURLSessionDownloadTask
NSURLSessionDataTask
/// Swift
URLSessionDataTask
URLSessionUploadTask
URLSessionDownloadTask

后台传输注意事项

当app处于暂停状态(前文提到的Suspended)时,NSURLSession类支持后台传输。后台传输只有在session被创建为后台类型(background session,上面提到的session的一种)时才能使用(该类型是经调用方法backgroundSessionConfiguration:的返回值得到,这个方法在iOS8以后不再使用,使用backgroundSessionConfigurationWithIdentifier:代替)。

由于真实的传输是基于进程进行的(传输层是基于进程的,网络层基于主机IP),而且重启进程的代价相对高昂,这会导致一些功能无法使用,所以对于后台session会有以下限制:

  • 该session必须提供了一个代理以便进行事件传递(对于上传和下载,代理的行为和进程内的传输类似);
  • 只支持HTTP和HTTPS协议(自定义协议不支持);
  • 始终遵循重定向;
  • 上传任务只支持文件(上传数据对象和流会在程序退出时失败);
  • 如果程序处于后台时创建后台传输任务,配置对象的discretionary属性会置为true;

提示

在iOS8和OS X 10.10之前,数据任务是不支持后台session的。

重新启动应用程序的行为在iOS和OS X之间略有不同。

在iOS中,当一个后台传输完成之后或者要求凭证时,如果app没有运行,那么iOS会自动在后台重启app,并调用app的UIApplicationDelegate对象的方法application:handleEventsForBackgroundURLSession:completionHandler:。调用的这个方法会返回导致我们应用程序重新启动的session标识符(identifier)和一个completionHandler,我们应该存储这个回调处理(completion handler会在任务完成之后使用它),并且根据该标识符创建一个后台配置对象,然后使用该配置对象创建一个新的session,这个新的session会自动与正在进行后台活动的session相关联。当该session处理完了最后的下载任务之后,它会给session的代理发送一个URLSessionDidFinishEventsForBackgroundURLSession:消息。在代理方法中,我们需要在主线程中调用先前保存的completion handler,以便让操作系统知道再次挂起app是安全的。

不管是在iOS和OS X中,当用户重新启动app时,我们都应立即获取上次程序运行时未完成任务session的标识符,并以该标示符创建后台配置对象,然后为配置对象创建一个session。这些新的会话也会自动与正在后台进行的活动重新关联。

✨✨✨ 提示

我们必须为每一个标识符创建一个session(在创建配置对象时指定)。因为多个session共享相同的的标识符的行为是未定义的。

当任务完成时如果我们的app是处于暂停状态,代理方法URLSession:downloadTask:didFinishDownloadingToURL:会被新下载的文件URL调用。

类似地,如果有请求凭证的任务,NSURLSession对象会适当地调用代理URLSession:task:didReceiveChallenge:completionHandler:或者URLSession:didReceiveChallenge:completionHandler: 方法。

当URL loading system的网络发生错误之后,后台session中的上传和下载任务会自动重试,因此完全没有必要使用可达性1相关的API来确定何时开始去重试失败的任务。

关于怎样使用NSURLSession来做后台传输,会在后面进行讲解。

生命周期和代理的相互影响(Life Cycle and Delegate Interaction)

想清楚我们要用NSURLSession类做什么,这将有助于全面的理解session的生命周期,包括session如何与它的代理进行交互,代理调用的顺序,当服务器返回重定向时发生了什么,当我们重新开始失败任务时发生了什么等等。关于URL Session完成的生命周期后面会详细讲解Life Cycle of a URL Session

NSCopying Behavior

session和任务对象均实现了NSCopying协议,如下:

  • 当我们在copy一个session和任务对象时,我们会获得相同的对象
  • 如果我们copy一个配置对象时,我们会获得一个新的拷贝并且可以独立的进行修改。

注解:

1.可达性:之前也提到了可达性,这里说一下我的理解(如果你对此理解地更好不妨告知我一下,我的联系方式在译本介绍中)。有过计算机网络相关知识的同学应该知道ICMP控制报文协议,在ICMP中有提到终点不可达(Type=3)、协议不可达(Type=4)、超时(Type=11)、参数问题(Type=12)和路由重定向(Type=5)等等差错报告报文。我们在诊断一个源到目的端链路中出现问题时,使用traceroute来进行测试(具体的测试原理是每经过一个路由器TTL值加一,并且报文携带的是一个不可达的端口号),其主要的手段便是使用终点不可达(不可达的一个端口号)和超时(TTL值为0)两种情况,我猜测这里面提到的可达性和这个有几分类似,也是一种用于测试客户端和服务端一种是否通信正常的API。traceroute程序,该程序和ping一样是基于ICMP的。

results matching ""

    No results matching ""