我有后端向我的应用发送通知消息以通知用户下载新数据集。当用户收到通知时,会在推送通知线程中创建警告框,并要求用户接受或拒绝数据集下载。如果用户接受下载,则会以异步方式下载数据。我想要做的是,我想在下载完成后刷新表格视图。但我在不同的主题上,我不知道如何从该主题更新Tableview
。我该怎么做?
func downloadContent(key: String, pinOnCompletion: Bool) {
let manager = AWSUserFileManager.defaultUserFileManager()
let content = manager.contentWithKey(self.prefix + key)
content.downloadWithDownloadType(
.IfNewerExists,
pinOnCompletion: pinOnCompletion,
progressBlock: {[weak self](content: AWSContent?, progress: NSProgress?) -> Void in
guard self != nil else { return }
/* Show progress in UI. */
},
completionHandler: {[weak self](content: AWSContent?, data: NSData?, error: NSError?) -> Void in
guard self != nil else { return }
if let error = error {
print("Failed to download a content from a server. \(error)")
return
}
if let fileData = data {
// Saves Data to core data here
// Update the tableViewController
}
print("Object download complete.")
})
}
更新-1
这不是重复的帖子。建议的重复帖子询问如何从Tableviewcontroller
类中的异步任务更新Tableviewcontroller
。我的问题是从另一个类的另一个线程更新Tableviewcontroller
。
更新-2
为了澄清,下载管理器类中的这个下载函数是从实现AmazonPushNotificationManager
的类中调用的。收到推送通知时会调用它。因此,当我调用下载时,我不再在UI线程上了。我是推送通知线程。如果我通过完成处理程序,那将来自推送通知线程,而不是来自UI。我有两个观点(一个是Tableview
,另一个是UIViewController
)。收到推送通知时,用户可以在任何一个上。因此,如果用户在UIViewController
上,我不应该重新加载表数据。我希望这听起来并不令人困惑。
答案 0 :(得分:2)
您不会从后台线程更新UI,而是切换回主线程,如下所示:
Swift 2:
dispatch_async(dispatch_get_main_queue()) {
self.tableView.reloadData()
}
...或
Swift 3
DispatchQueue.main.async {
self.tableView.reloadData()
}
答案 1 :(得分:2)
正如其他人所说,你不从后台线程更新表视图控制器等UI对象。这是明确禁止的。
你想要做的是在你的下载管理器类中编写一个函数(如果这是类是什么),它需要一个完成处理程序。编写downloadContent函数,以便在下载完成后调用完成处理程序。我在Github上有一个名为Async_demo(链接)的示例项目,它正好演示了这种技术。 (这个项目是用Swift 3编写的。此时你应该在Swift 3中进行新的开发。为什么你现在已经发布了Swift 3的Swift 2?)
关键功能是:
/**
This function demonstrates handling an async task.
- Parameter url The url to download
- Parameter completion: A completion handler to execute once the download is finished
*/
func downloadFileAtURL(_ url: URL, completion: @escaping DataClosure) {
//We create a URLRequest that does not allow caching so you can see the download take place
let request = URLRequest(url: url,
cachePolicy: .reloadIgnoringLocalAndRemoteCacheData,
timeoutInterval: 30.0)
let dataTask = URLSession.shared.dataTask(with: request) {
//------------------------------------------
//This is the completion handler, which runs LATER,
//after downloadFileAtURL has returned.
data, response, error in
//Perform the completion handler on the main thread
DispatchQueue.main.async() {
//Call the copmletion handler that was passed to us
completion(data, error)
}
//------------------------------------------
}
dataTask.resume()
//When we get here the data task will NOT have completed yet!
}
}