iOS NSURLSession使用自定义委托处理数据任务的完成

iOS NSURLSession使用自定义委托处理数据任务的完成,ios,swift,cocoa-touch,ios8,Ios,Swift,Cocoa Touch,Ios8,我的最终目标是在后台发出http请求,同时在内存中处理响应。据我所知,后台请求必须通过自定义委托进行(这意味着我不能使用dataTaskWithRequest(request,completionHandler)),而要处理内存中的响应,我必须使用数据任务(这意味着我不能将下载任务与URLSession一起使用)(会话、下载任务、完成下载课程)) 根据这一点:似乎没有任何委托方法在完成数据任务时被调用。这是通过委托处理响应的唯一方法,通过URLSession(会话、数据任务、数据)处理单个NSD

我的最终目标是在后台发出http请求,同时在内存中处理响应。据我所知,后台请求必须通过自定义委托进行(这意味着我不能使用
dataTaskWithRequest(request,completionHandler)
),而要处理内存中的响应,我必须使用数据任务(这意味着我不能将下载任务与
URLSession一起使用)(会话、下载任务、完成下载课程)


根据这一点:似乎没有任何委托方法在完成数据任务时被调用。这是通过委托处理响应的唯一方法,通过
URLSession(会话、数据任务、数据)处理单个NSData片段
?:没有委托方法将整个最终响应作为单个NSData实例处理?

对于少量数据,如API调用或小图像,如要立即显示的化身,
dataTaskWithRequest(请求,completionHandler)
是您想要的方法。它设置了一个异步任务,这意味着当您启动任务时,执行将立即返回到代码,任务将负责下载数据并在“后台”内存中缓冲当你的应用程序正在运行时。一旦所有下载任务完成,它将调用你的completionHandler,让它知道它已完成,并且数据已准备就绪。它将数据作为参数传递给你的处理程序

对于较大的文件,如播客、视频和大型图像,即使用户开始查看另一个应用程序,并且您的应用程序已挂起,您也希望iOS为您下载该文件。然后,您将希望使用具有后台会话配置
backgroundSessionConfigurationWithIdentifier:
和自定义委托的ate需要实现方法
URLSession:downloadTask:DidFinishDownloadingTour:
。调用此方法时,您可以在
url
处读取文件内容,该文件将使用以下代码传递给您:

let data = NSData(contentsOfURL: url)
iOS应用程序退出后持续的后台下载之所以会这样处理,是因为iOS希望能够代表播客、视频等不同应用程序继续下载多个文件。如果用户在高速网络上,在内存中下载多个大文件可能会快速消耗所有设备的内存,同样,在使用
NSData(contentsOfURL:)
将整个文件读入内存之前,您应该记住文件的大小

下面是一个如何将所有内容组合在一起的工作示例。将其粘贴到iOS操场上,然后查看您将获得的图像:

import UIKit

class MyDelegate: NSObject, NSURLSessionDelegate, NSURLSessionDownloadDelegate {
  func URLSession(session: NSURLSession, downloadTask: NSURLSessionDownloadTask, didFinishDownloadingToURL location: NSURL) {
    if let data = NSData(contentsOfURL: location) {
      // work with data ...
      UIImage(data: data)
    }
  }
}

let configuration = NSURLSessionConfiguration.backgroundSessionConfigurationWithIdentifier("my-session-identifier")
let delegate = MyDelegate()
let session = NSURLSession(configuration: configuration, delegate: delegate, delegateQueue: nil)
let url = NSURL(string: "https://pbs.twimg.com/profile_images/473550724433858560/tuHsaI2U.png")!
let task = session.downloadTaskWithURL(url)
task.resume()

// this allows the code to run in a playground
import XCPlayground
XCPlaygroundPage.currentPage.needsIndefiniteExecution = true

如果我正确理解了你应该执行的文档

func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?)
方法,它“告诉委托任务已完成数据传输”(按文档)。 对于
error
,将使用
nil
值调用它,但您还必须检查
task.response
是否存在潜在问题

在此之前,您应该通过
URLSession:dataTask:didReceiveData:
调用手动收集数据片段:

此委托方法可能被调用多次,每次调用仅提供自上次调用以来收到的数据。如果需要,应用程序负责累积此数据


没有委托方法可以将所有数据组合成单个对象,您必须手动操作。

苹果的文档给我的印象是,您不能使用
dataTaskWithRequest(request,completionHandler)
如果要在后台处理响应,必须使用
nsurlsessionelegate
,它通过一些复杂的过程(甚至还没有实现…)在应用程序生命周期中实例化@user1084447一开始我误解了你在后台的意思。我已经扩展了答案,以解决iOS应用程序的后台问题。希望这能解决问题!@hashemi无需使用NSData。你可以使用UIImage(contentsOfFile:location.path!)@LeoDabus正确。OP需要NSData,所以我不想跳过这一步。UIImage很重要。谢谢@hashemi。我想尝试将响应保留在内存中的原因是1)我调用我们自己的api,控制各个响应大小,并确保它们保持较小;2)我将解析响应并更新一个持久的SQLite存储,所以从磁盘读取一个文件来更新磁盘上的SQLite存储对我来说就像是浪费io。。。我找到了另一份文档,它证实了在数据任务中实现这一点的唯一方法是手动处理片段(仅在ios8+中可能)。我将尝试这两种方法并进行比较。