ios

NSURLSession(URL会话)

2017-02-26  本文已影响723人  Mob_Developer

概述

NSURLSession类和其相关的类提供了下载内容的API.此类提供了丰富的代理方法集合以支持验证并且在应用没有运行时,或者在iOS中处于挂起状态时,也能够在后台下载。

NSURLSession类原生支持datafileftphttphttps

使用NSURLSessionAPI,应用可能创建一个或者多个sessions,每一个session协调一组相关的数据传输任务。比如,写一个web浏览器,应用可能为每一个标签页或者窗口创建一个session,或者为交互中的用户创建一个session并为后台下载创建另一个session。在每一个session中应用为其添加一系列的任务,每一个任务代表一个指定URL请求。

一个URLSession中的任务共享一个配置对象,配置对象定义了连接行为,比如同时连接到同一个服务器的最大连接数量,是否允许蜂窝网络连接,等等。会话的行为部分由创建其配置对象时调用的方法决定:

session配置对象同时包含URL缓存和Cookie存储对象的引用,这些引用在创建请求或者处理响应时可能会用到,取决于配置和请求类型。

session的任务也共享一个代理,允许你在认证失败,当数据从服务器返回,当准备缓存数据等多个事件发生时提供和获取信息。对于所有后台下载和上传,必须提供一个遵循了NSURLSessionDownloadDelegate协议的代理。另外如果不需要代理提供的任何功能,可以在创建session时传入nil,也就是不提供其代理对象。

重要
session对象对代理是强引用直到应用退出或者显式地销毁session。如果不销毁session,在应用未退出前会一直泄漏内存。

在session中创建任务以上传数据到服务器,然后从服务器获取数据转换为文件放在磁盘或者转换为NSData存放在内存中。NSURLSession提供了三种任务类型:

和大多数网络API一样,NSURLSessionAPI是异步的。它以两种方式中的一种返回数据,基于调用的方法:

向代理分发信息之外,NSURLSessionAPI提供状态和进度属性。如果需要可以查询它们,根据当前的任务状态做程序决议。

URL session同时支持取消、重启、恢复和挂起任务,并能够在挂起、取消、下载失败的位置恢复任务。

URL Session类层级

NSURLSessionAPI包含以下类:

另外,NSURLSessionAPI提供了四个协议,应用可以实现这些协议定义的代理方法,从而对 `session和任务行为提供更细粒度的控制。

最后,NSURLSession也使用其他常用的类,比如NSURLConnectionNSURLDownload。其中一些共享类如下:

验证和TLS自定义

当服务器请求身份验证或在TLS协商期间提供凭据时,URL会话将调用其代理上的方法,以允许以自定义方式处理身份验证或证书验证。 它调用的方法取决于您是处理任务特定的挑战(task-specific challenge)还是会话范围的挑战(session-wide challenge)。 表1显示了两者之间的差异。

chanllenge_deferences.png

对于任务特定的挑战,会话调用它代理的URLSession:task:didReceiveChallenge:completionHandler:方法。

对于会话范围的验证挑战,会话调用它代理的URLSession:didReceiveChallenge:completionHandler:方法,如果有这个方法。否则,调用它代理的URLSession:task:didReceiveChallenge:completionHandler:方法。

然后,如果凭据不可用,或者服务器拒绝凭据,连接将继续进行而不进行身份验证。 对于HTTP和HTTPS请求,连接尝试失败,并给出相应的HTTP状态代码,并可能提供可选的内容(例如私有站点的公开版本)。 对于其他URL类型(如FTP),返回连接失败的结果。

** 注意 **
Kerberos认证是透明处理的。 这里描述的委托方法不适用于Kerberos身份验证。

应用传输安全(App Transport Security, ATS)

从iOS 9.0和OS X v10.11开始,对于使用NSURLSession所做的所有HTTP连接,默认情况下启用一个名为App Transport Security(ATS)的新安全功能。 ATS要求HTTP连接使用HTTPS(RFC 2818)。

有关详细信息,请参阅 Information Property List Key Reference中的NSAppTransportSecurity。

使用URL Session

使用NSURLSession类创建请求”

  1. 创建会话配置对象。对于后台会话,配置必须包含唯一的标识。保存这个标识,如果应用崩溃、退出或者挂起,使用它和会话重新关联起来。
  2. 创建会话,指定配置对象,代理可选。
  3. 在会话中创建任务对象,每一个任务代表一个资源请求。这个任务对象是NSURLSessionTask子类 - NSURLSessionDataTask, NSURLSessionUploadTask, 或者NSURLSessionDownloadTask的对象,取决于要实现的行为。
 每个任务处于挂起状态,当应用调用任务的`resume`之后,它开始下载指定的资源。

开启任务之后,会话调用它的代理方法,如下:

  1. 如果与服务器的初次握手需要连接级挑战(比如SSL客户端证书),NSURLSession调用URLSession:task:didReceiveChallenge:completionHandler:或者`URLSession:didReceiveChallenge:completionHandler: 代理方法,如前面验证和TLS自定义里面描述的一样。
    关于会话验证代理方法的更多信息,查看URL Session Programming Guide。

  2. 如果任务数据由流(stream)提供,NSURLSession对象调用代理的URLSession:task:needNewBodyStream:方法以获取NSInputStream对象,这个对象为新的请求提供了请求体数据。

  3. 在想服务器上传请求提数据期间,代理周期性的接收URLSession:task:didSendBodyData:totalBytesSent:totalBytesExpectedToSend:回调,报告上传进度。

  4. 服务器发送响应。

  5. 如果响应指示需要验证,会话调用它代理的URLSession:task:didReceiveChallenge:completionHandler:方法。回到第2步。

  6. 如果是一个HTTP重定向响应。NSURLSession对象调用代理的URLSession:task:willPerformHTTPRedirection:newRequest:completionHandler:方法。代理方法调用提供的完成处理者,并传递NSURLRequest对象(遵从重定向),一个新的NSURLRequest对象(重定向到其他URL),或者nil(把重定向响应体作为有效响应,并作为结果返回)。

*  如果遵从重定向,回到第2步;
*  如果代理没有实现这个方法,重定向会跟踪到最大重定向数。
  1. 通过 downloadTaskWithResumeData: 或者downloadTaskWithResumeData:completionHandler:方法创建的(重新)下载任务,NSURLSession调用代理的URLSession:downloadTask:didResumeAtOffset:expectedTotalBytes: 方法,并传入一个新的任务对象。

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

  3. 从服务器传输数据期间,代理周期性地接收任务级回调以报告传输进度。

    对于数据任务,会话在接收到实际的数据片段时调用代理的URLSession:dataTask:didReceiveData:方法。

    对于下载任务,会话调用委托的·、URLSession:downloadTask:didWriteData:totalBytesWritten:totalBytesExpectedToWrite:方法,并传入已成功写入磁盘的字节数。 如果用户告诉应用暂停下载,调用cancelByProducingResumeData:方法取消该任务。

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

  4. 对于data task,NSURLSession对象可能调用代理的URLSession:dataTask:willCacheResponse:completionHandler:方法。之后应用应该决定要不要缓存。如果不实现这个方法,默认的行为是使用会话配置对象中的指定的缓存策略。

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

  6. 如果一个下载任务成功完成,NSURLSession对象调用任务的URLSession:downloadTask:didFinishDownloadingToURL:,并传入临时文件的位置。应用必须从文件读取响应数据或者在代理方法返回之前把文件移动到持久存储的位置。

  7. 任何任务完成时,NSURLSession对象调用代理的URLSession:task:didCompleteWithError:方法,并传入一个error对象或者nil(如果任务顺利完成)。

  如果任务能够恢复,`NSError`对象的`userInfo`字典包含与` NSURLSessionDownloadTaskResumeData `键对应的值。应用应该使用这个值调用 `downloadTaskWithResumeData: `或者`downloadTaskWithResumeData:completionHandler:`创建一个新的下载任务以继续已有的下载。

   如果任务不能恢复,应用应该创建一个新的下载任务,从开始重新下载。

   不论哪种情况,只要不是服务器错误导致的传输失败,回到第3步(创建和恢复任务对象)。

    > ** 注意 **
    NSURLSession不通过`error`参数报告服务器错误。代理从`error`参数接收到的错误都是客户端错误,比如不能解析或者连接到主机。错误码在`URL Loading System Error Codes`中有描述。

   > 服务端错误由`NSHTTPURLResponse ` 对象中的`HTTP`状态码报告。更多信息,参阅`NSHTTPURLResponse` 和 `NSURLResponse `   类的文档。
  1. 如果不在需要session对象,可以调用invalidateAndCancel (取消未完成的任务) 或者 finishTasksAndInvalidate (在作废会话对象之前允许未完成的任务继续完成)以作废其对象。如果不作废session对象,它会在应用程序终止时自动消失(除非它是有激活任务的后台会话)。
作废会话之后,当所有未完成的任务取消或者完成时,会话对象调用代理的`URLSession:didBecomeInvalidWithError: `方法。当这个代理方法返回时,代理对象清除其对代理的强引用。

如果应用取消了正在进行中的下载,NSURLSession调用代理的URLSession:task:didCompleteWithError:,和发生错误一样。

后台传输注意事项

因为重启应用(或者等待用户重新加载)代价相对更高,一些功能在后台会话中是不可用的。结果就是:

如果这些限制和你的应用需求冲突,你可以在非后台会话中下载远程资源到一个文件中。如果你这样做,当用户把你的iOS应用放到后台或者退出MacOS应用时,调用cancelByProducingResumeData:方法暂停所有激活的下载。当用户把应用重新带到前台时,恢复下载。如果应用在获取恢复数据(resume data)之前就终止了,就不能再恢复下载。

** 注意 **
后台会话是优化后用于传输数量较少、能够在必要时恢复的大资源。你可能想调研优化服务器端行为的方法,以便于此类使用,比如:

NSCoping行为

会话和任务遵守NSCoping协议,如下:

线程安全

URL session API自身是是线程安全的。能够随意的在任何线程上下文创建会话和任务,当代理方法调用提供的完成处理者(completion handler)时,一切将自动安排在正确的代理队列上。

警告
URLSessionDidFinishEventsForBackgroundURLSession:代理方法可能会在其他线程调用。然而,在iOS中,你对这个方法的实现可能需要调用app代理的application:handleEventsForBackgroundURLSession:completionHandler:方法中提供的完成处理者。必须在主线程中调用完成处理者。

上一篇下一篇

猜你喜欢

热点阅读