正在更新 UI Dispatch_Async 后台下载 Swift
Updating UI Dispatch_Async background download Swift
我正在开发一个 folders/files 应用程序,用户可以在其中将文件下载到本地磁盘。每当用户下载文件时,我想显示一个显示进度的下载栏。
为此,我创建了一个协议,允许我的下载 class 和我的视图控制器进行通信:
协议:
protocol DownloadResponder : class {
func downloadFinished()
func downloadProgress(current:Int64, total:Int64)
}
下载class:
class fileDownloader: NSObject, NSURLSessionDelegate, NSURLSessionDownloadDelegate {
//responder
var responder : MyAwesomeDownloadResponder?
init(responder : MyAwesomeDownloadResponder) {
self.responder = responder
}
...
func URLSession(session: NSURLSession, downloadTask: NSURLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) {
println("downloaded \(100*totalBytesWritten/totalBytesExpectedToWrite)")
responder?.downloadProgress(totalBytesWritten, total: totalBytesExpectedToWrite)
}
...
}
然后在我的视图控制器中我有触发 downloadProgress
函数的下载按钮:
func downloadProgress(current:Int64, total:Int64) {
let priority = DISPATCH_QUEUE_PRIORITY_DEFAULT
dispatch_async(dispatch_get_global_queue(priority, 0)) {
// do some task
var currentProgress = 100 * current / total
dispatch_async(dispatch_get_main_queue()) {
// update some UI
self.downloadLbl.text = "Downloaded \(currentProgress)%"
//set progress bar
self.progressBar.setProgress(Float(currentProgress), animated: true)
}
}
}
虽然在控制台中打印信息一直有效,但更新 UI 并不是很稳定。为了解决这个问题,我使用了 dispatch_async 方法在主线程上推送 UI 更改。然而,虽然它始终在第一次运行,但会弹回到前一个视图控制器并再次返回,再次执行下载不会触发 UI 更新。进度条 progressBar.setProgress
什么都不做,我的标签 downloadLbl.text
不会自行更新。
有没有人知道解决这个问题的方法?
如果我的问题缺少信息,请告诉我,我会尝试添加现有信息。谢谢!
因为我没有收到/找到任何解决我问题的方法,我回到了更高的层次并改变了我的 classes 之间的通信方式以处理 ui 基于背景的变化下载线程进度。
我没有使用协议,而是使用了通知,它解决了我的问题。
里面下载class:
func URLSession(session: NSURLSession, downloadTask: NSURLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) {
println("downloaded \(100*totalBytesWritten/totalBytesExpectedToWrite)")
//NOTIFICATION
// notify download progress!
var fileInfo = [NSObject:AnyObject]()
fileInfo["fileId"] = fileDownloader.storageInfo[downloadTask.taskIdentifier]!["id"] as! Int!
fileInfo["fileCurrent"] = Float(totalBytesWritten)
fileInfo["fileTotal"] = Float(totalBytesExpectedToWrite)
let defaultCenter = NSNotificationCenter.defaultCenter()
defaultCenter.postNotificationName("DownloadProgressNotification",
object: nil,
userInfo: fileInfo)
}
在视图控制器内:
override func viewDidLoad() {
super.viewDidLoad()
// ready for receiving notification
let defaultCenter = NSNotificationCenter.defaultCenter()
defaultCenter.addObserver(self,
selector: "handleCompleteDownload:",
name: "DownloadProgressNotification",
object: nil)
}
func handleCompleteDownload(notification: NSNotification) {
let tmp : [NSObject : AnyObject] = notification.userInfo!
// if notification received, change label value
var id = tmp["fileId"] as! Int!
var current = tmp["fileCurrent"] as! Float!
var total = tmp["fileTotal"] as! Float!
var floatCounter = 100 * current / total
var progressCounter = String(format: "%.f", floatCounter)
if(id == self.fileId){
let priority = DISPATCH_QUEUE_PRIORITY_DEFAULT
dispatch_async(dispatch_get_global_queue(priority, 0)) {
// do some task
dispatch_async(dispatch_get_main_queue()) {
// update some UI
self.downloadLbl.text = "Downloaded \(progressCounter)%"
self.progressBar.setProgress((progressCounter as NSString).floatValue, animated: true)
}
}
}
}
希望对您有所帮助!
我正在开发一个 folders/files 应用程序,用户可以在其中将文件下载到本地磁盘。每当用户下载文件时,我想显示一个显示进度的下载栏。
为此,我创建了一个协议,允许我的下载 class 和我的视图控制器进行通信:
协议:
protocol DownloadResponder : class {
func downloadFinished()
func downloadProgress(current:Int64, total:Int64)
}
下载class:
class fileDownloader: NSObject, NSURLSessionDelegate, NSURLSessionDownloadDelegate {
//responder
var responder : MyAwesomeDownloadResponder?
init(responder : MyAwesomeDownloadResponder) {
self.responder = responder
}
...
func URLSession(session: NSURLSession, downloadTask: NSURLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) {
println("downloaded \(100*totalBytesWritten/totalBytesExpectedToWrite)")
responder?.downloadProgress(totalBytesWritten, total: totalBytesExpectedToWrite)
}
...
}
然后在我的视图控制器中我有触发 downloadProgress
函数的下载按钮:
func downloadProgress(current:Int64, total:Int64) {
let priority = DISPATCH_QUEUE_PRIORITY_DEFAULT
dispatch_async(dispatch_get_global_queue(priority, 0)) {
// do some task
var currentProgress = 100 * current / total
dispatch_async(dispatch_get_main_queue()) {
// update some UI
self.downloadLbl.text = "Downloaded \(currentProgress)%"
//set progress bar
self.progressBar.setProgress(Float(currentProgress), animated: true)
}
}
}
虽然在控制台中打印信息一直有效,但更新 UI 并不是很稳定。为了解决这个问题,我使用了 dispatch_async 方法在主线程上推送 UI 更改。然而,虽然它始终在第一次运行,但会弹回到前一个视图控制器并再次返回,再次执行下载不会触发 UI 更新。进度条 progressBar.setProgress
什么都不做,我的标签 downloadLbl.text
不会自行更新。
有没有人知道解决这个问题的方法? 如果我的问题缺少信息,请告诉我,我会尝试添加现有信息。谢谢!
因为我没有收到/找到任何解决我问题的方法,我回到了更高的层次并改变了我的 classes 之间的通信方式以处理 ui 基于背景的变化下载线程进度。
我没有使用协议,而是使用了通知,它解决了我的问题。
里面下载class:
func URLSession(session: NSURLSession, downloadTask: NSURLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) {
println("downloaded \(100*totalBytesWritten/totalBytesExpectedToWrite)")
//NOTIFICATION
// notify download progress!
var fileInfo = [NSObject:AnyObject]()
fileInfo["fileId"] = fileDownloader.storageInfo[downloadTask.taskIdentifier]!["id"] as! Int!
fileInfo["fileCurrent"] = Float(totalBytesWritten)
fileInfo["fileTotal"] = Float(totalBytesExpectedToWrite)
let defaultCenter = NSNotificationCenter.defaultCenter()
defaultCenter.postNotificationName("DownloadProgressNotification",
object: nil,
userInfo: fileInfo)
}
在视图控制器内:
override func viewDidLoad() {
super.viewDidLoad()
// ready for receiving notification
let defaultCenter = NSNotificationCenter.defaultCenter()
defaultCenter.addObserver(self,
selector: "handleCompleteDownload:",
name: "DownloadProgressNotification",
object: nil)
}
func handleCompleteDownload(notification: NSNotification) {
let tmp : [NSObject : AnyObject] = notification.userInfo!
// if notification received, change label value
var id = tmp["fileId"] as! Int!
var current = tmp["fileCurrent"] as! Float!
var total = tmp["fileTotal"] as! Float!
var floatCounter = 100 * current / total
var progressCounter = String(format: "%.f", floatCounter)
if(id == self.fileId){
let priority = DISPATCH_QUEUE_PRIORITY_DEFAULT
dispatch_async(dispatch_get_global_queue(priority, 0)) {
// do some task
dispatch_async(dispatch_get_main_queue()) {
// update some UI
self.downloadLbl.text = "Downloaded \(progressCounter)%"
self.progressBar.setProgress((progressCounter as NSString).floatValue, animated: true)
}
}
}
}
希望对您有所帮助!