2

我在使用框架时有一些误解NSURLSession,这就是为什么我决定在没有 AFFramework/Alamofire 的情况下从头开始编写小应用程序。

我有一个 API 需要以下步骤来上传文件:

  1. POST 文件数据
  2. 获取响应 (JSON)
  3. 将一些 json 字段发布到api/save

我有这样一个配置的后台会话:

let configuration = NSURLSessionConfiguration.backgroundSessionConfigurationWithIdentifier("myBackground")
let session = NSURLSession(configuration: configuration, delegate: self, delegateQueue: nil)

我已经实现了两种方法:

func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask, didReceiveData data: NSData)

我汇总所有数据的地方

func URLSession(session: NSURLSession, task: NSURLSessionTask, didCompleteWithError error: NSError?)

我将这些数据转换为响应对象。这个响应对象对我来说非常重要。

一切正常,而应用程序在前台,但我在后台遇到问题。

情况1

开始上传数据后,应用程序立即崩溃。根据WWDC,我需要实施

func application(application: UIApplication, handleEventsForBackgroundURLSession identifier: String, completionHandler: () -> Void)

didCompleteWithError并在方法中调用此处理程序。但在调用此方法之前,我需要api/save使用上传响应中的数据进行调用。我怎样才能得到这些数据?

案例2

大部分情况类似。用户在上传过程中停止应用程序。比在几秒钟内加载应用程序,而会话适用于我的任务。现在会话调用didReceiveData,但当然,一些数据丢失。在这种情况下我该怎么办?如何恢复响应数据?

4

2 回答 2

2

您没有提到实施URLSessionDidFinishEventsForBackgroundURLSession(一种NSURLSessionDelegate方法)。你真的很想实现它。基本流程是:

  • 在应用程序委托中handleEventsForBackgroundURLSession,您应该:

    • 启动后台NSURLSession(它将开始接收与所有上传相关的委托方法调用);和
    • 保存完成处理程序(但不要调用它)。
  • 然后,在URLSessionDidFinishEventsForBackgroundURLSession(当您处理完所有响应后),您调用保存在handleEventsForBackgroundURLSession. (确保将其分派到主队列。)

如果您正在执行所有这些操作,那么当后台会话重新启动时,didReceiveData呼叫将与对您的各种上传的响应一起出现。

我刚刚做了一个快速测试,上传了 5 张 20mb 的图片并立即终止了应用程序。然后,即使应用程序没有运行,我也看到五个文件慢慢出现在我的服务器上(显然由守护进程处理)。当所有五个都完成后,应用程序在后台透明地重新启动,handleEventsForBackgroundURLSession被调用(重新启动会话),它让所有didReceiveData调用都被快速调用,完成后,URLSessionDidFinishEventsForBackgroundURLSession被调用,然后我的应用程序才调用保存完成处理程序。

就为什么这对您不起作用而言,不足以诊断问题。可能性包括:

  • 也许您不恰当地终止了该应用程序。您不能通过双击主页按钮并在那里终止应用程序来终止应用程序;您必须让它自己自然终止,或者出于诊断/测试目的,我通过调用exit(0)代码强制它终止。

  • handleEventsForBackgroundURLSession也许您在被调用时没有重新启动会话。

  • 也许您过早地调用了提供的完成处理程序(即URLSessionDidFinishEventsForBackgroundURLSession调用之前)。

很难说,但我怀疑您的实现中隐藏着一些不太正确的东西,并且根据提供的信息很难说出它是什么(假设它不是上述几点)。不幸的是,调试这个后台会话非常复杂,因为当应用程序终止时,它不再附加到调试器,所以你不能轻易调试应用程序被 iOS 自动重启后发生的事情)。就个人而言,我要么NSLog发送消息,然后只查看设备控制台(以及查看服务器上显示的内容),要么在应用程序本身中构建一些持久日志记录机制。

于 2016-01-15T23:57:39.447 回答
0

为了测试后台会话代码,建议在真实设备上进行测试。在编写使用 NSURLSession 的后台会话支持的应用程序时,很容易被开发过程中的三个不明显的工件混淆:

  • 当您从 Xcode 运行您的应用程序时,Xcode 会将该应用程序安装在一个新容器中,这意味着您的应用程序的路径会发生变化。这可能会混淆 NSURLSession 的后台会话支持。 注意:此问题已在 iOS 9 中修复;如果您在 iOS 9 或更高版本中遇到 NSURLSession 无法处理容器路径更改的问题,请提交错误。
  • Xcode 的调试可防止系统挂起您的应用程序。因此,如果您从 Xcode 运行您的应用程序,或者您在启动后的某个时间附加到该进程,然后将您的应用程序移动到后台,您的应用程序将在系统会暂停它的情况下继续执行。
  • 同样,iOS Simulator 也无法准确模拟 app 的挂起和恢复;这在过去有效,但在 iOS 8 或 iOS 9 模拟器中不起作用。

资料来源:苹果开发者论坛

于 2016-02-16T09:16:38.703 回答