NSURLSessionUploadTask获取响应数据

时间:2016-01-13 07:00:33

标签: ios nsurlsession nsurlsessionuploadtask

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

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

  1. POST文件数据
  2. 获取回复(JSON)
  3. 将一些json字段发布到api/save
  4. 我有这样的配置后台会话:

    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,但当然缺少一些数据。在这种情况下我该怎么办?如何恢复响应数据?

2 个答案:

答案 0 :(得分:2)

您没有提及实施URLSessionDidFinishEventsForBackgroundURLSessionNSURLSessionDelegate方法)。你真的想要实现它。基本过程是:

  • 在app delegate的handleEventsForBackgroundURLSession中,你应该:

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

如果您正在执行所有这些操作,那么当重新启动后台会话时,didReceiveData来电将会显示您对各种上传内容的回复。

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

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

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

  • 在调用handleEventsForBackgroundURLSession时,您可能没有重启会话。

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

很难说,但我怀疑你的实施中埋藏了一些不太正确的东西,根据所提供的信息很难说它是什么(假设它不是上述点之一)。不幸的是,调试这些后台会话非常复杂,因为当应用程序终止时,它不再附加到调试器,因此您无法轻松调试iOS自动重启应用程序后发生的情况。就个人而言,我要么NSLog消息,只是观察设备控制台(以及观察服务器上显示的内容),或者我在应用程序本身中构建了一些持久性日志记录机制。

答案 1 :(得分:0)

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

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

来源:Apple Developer Forum