【问题标题】:Application going to background, data is not loaded应用程序进入后台,未加载数据
【发布时间】:2017-03-30 04:44:23
【问题描述】:

我创建了一个简单的 json 应用程序并且工作正常,但是当应用程序进入后台数据未加载时,请有人建议我提供代码。

    let task = URLSession.shared.dataTask(with: URL(string: "http://tour-pedia.org/api/getReviews?location=Rome&category=poi")!) { (data, response , error) in
    if error != nil {
        print(error?.localizedDescription ?? "")
    }
    if let resultArray = (try? JSONSerialization.jsonObject(with: data!, options: [])) as? [[String:Any]] {
        for jsonreviews in resultArray {
            let review = Review()
            review.rating = jsonreviews["rating"] as? Int ?? 0
            review.text = jsonreviews["text"] as! String
            review.time = jsonreviews["time"] as! String
            reviews.append(review)
        }
        DispatchQueue.main.async {
            self.tableview.reloadData()   // if you use tableview
        }
    }
}
task.resume()

【问题讨论】:

  • 我注意到您正在后台线程上更新reviews。如果您的 UITableViewDataSource 方法正在引用它,您确实应该构建一个本地数组,然后将其复制到主线程上的数据源(或以某种方式同步您对它的访问)。另外,reviews 是全球性的吗?

标签: ios json swift3


【解决方案1】:

如果您只需要额外的几分钟来完成请求,简单的解决方案是请求操作系统一点时间来完成此操作。见Background Execution: Executing Finite-Length Tasks

因此,如果在任务运行时应用碰巧被挂起,要告诉操作系统您可能需要一点额外时间来运行请求,您可以这样做:

var backgroundTask = UIBackgroundTaskInvalid

backgroundTask = UIApplication.shared.beginBackgroundTask(withName: "com.domain.app.data") {
    // do whatever clean up you want before your app exits

    UIApplication.shared.endBackgroundTask(backgroundTask)
    backgroundTask = UIBackgroundTaskInvalid
}

而且,当任务完成时:

if backgroundTask != UIBackgroundTaskInvalid {
    UIApplication.shared.endBackgroundTask(backgroundTask)
    backgroundTask = UIBackgroundTaskInvalid
}

因此:

var backgroundTask = UIBackgroundTaskInvalid

backgroundTask = UIApplication.shared.beginBackgroundTask(withName: "com.domain.app.data") {
    // do whatever clean up you want before your app exits

    UIApplication.shared.endBackgroundTask(backgroundTask)
    backgroundTask = UIBackgroundTaskInvalid
}

let task = URLSession.shared.dataTask(with: URL(string: "http://tour-pedia.org/api/getReviews?location=Rome&category=poi")!) { data, response, error in
    guard let data = data, error != nil else {
        print(error?.localizedDescription ?? "")
        return
    }

    if let resultArray = (try? JSONSerialization.jsonObject(with: data)) as? [[String: Any]] {
        for jsonreviews in resultArray {
            let review = Review()
            review.rating = jsonreviews["rating"] as? Int ?? 0
            review.text = (jsonreviews["text"] as! String)
            review.time = (jsonreviews["time"] as! String)
            reviews.append(review)
        }
        DispatchQueue.main.async {
            self.tableview.reloadData()   // if you use tableview
        }
    }

    if backgroundTask != UIBackgroundTaskInvalid {
        UIApplication.shared.endBackgroundTask(backgroundTask)
        backgroundTask = UIBackgroundTaskInvalid
    }
}
task.resume()

如果您认为完成查询需要超过几分钟的时间,您可以实现后台 URLSession,尽管对于这种情况来说这可能是多余的。它需要进行很多更改,包括:

  • 使用基于委托的URLSession
  • 使用下载任务而不是数据任务;
  • 确保实现应用委托方法以响应后台网络请求的完成;

【讨论】:

  • 我在使用基于委托的 URLSession 和下载任务时没有发现任何区别
  • @udaykumar - 实例化URLSession 时是否使用了背景URLSessionConfiguration?您是否在您的应用程序委托中实现了handle​Events​For​Background​URLSession 调用?您是否在 url​Session​Did​Finish​Events 中调用了保存的完成处理程序?
  • 是的,我做到了,但我没有调用 URL 会话并完成了事件
  • 你不要打电话给url​Session​Did​Finish​Events。您在 URLSessionDelegate 中实现它,操作系统调用它。通常,您只需让您的实现调用在handle​Events​For​Background​URLSession 中传递给您的完成处理程序。
  • 但是让我们暂时离开这个问题,看看你的陈述,“当应用程序进入后台时,数据未加载”......如果应用程序在后台,如果你是仅使用您的UITableViewDataSource 使用的变量(当应用程序最终暂停时丢失),我不确定我是否理解“未加载”的意思。
【解决方案2】:
猜你喜欢
  • 2018-07-10
  • 1970-01-01
  • 2011-09-12
  • 2011-04-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多