更新UI Dispatch_Async后台下载Swift



我正在开发一个文件夹/文件应用程序,用户可以在其中下载文件到本地磁盘。当用户下载文件时,我想要显示一个显示进度的下载栏。

为了做到这一点,我创建了一个协议,允许我的下载类和我的视图控制器进行通信:

协议:

protocol DownloadResponder : class {
    func downloadFinished()
    func downloadProgress(current:Int64, total:Int64)
}

下载类:

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不更新自己。

有谁知道解决这个问题的方法吗?如果我的问题缺少信息,请让我知道,我会尽量把现有的信息加起来。谢谢!

由于我没有收到/找到任何解决我的问题的方法,我回到了更高的层次,并改变了我的类之间的通信方式,以处理基于后台下载线程进程的ui更改。

我没有使用协议,而是使用通知,这解决了我的问题。

在下载类中:

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)
                        }
                    }
        }
    }

希望这对你有帮助!

最新更新