Swift 3 DispatchQueue.global(从 Firebase 下载图像并 UI 冻结)

Swift 3 DispatchQueue.global (download images from Firebase and UI frozen)

我对这个方法有疑问:

func DownloadImages(uid: String, indice: Int) {    
    DispatchQueue.global(qos: .background).async {
        let refBBDD = FIRDatabase.database().reference().child("users").child(uid)
        refBBDD.observeSingleEvent(of: .value, with: { snapshot in
            let snapshotValue = snapshot.value as? NSDictionary
            let profileImageUrl = snapshotValue?.value(forKey: "profileImageUrl") as! String

            let storage = FIRStorage.storage()
            var reference: FIRStorageReference!

            if(profileImageUrl == "") {
                return
            }
            print("before")

            reference = storage.reference(forURL: profileImageUrl)
            reference.downloadURL { (url, error) in
                let data = NSData(contentsOf: url!)
                let image = UIImage(data: data! as Data)

                print("image yet dowload ")
                self.citas[indice].image = image

                DispatchQueue.main.async(execute: { () -> Void in
                    self.tableView.reloadRows(at: [IndexPath(row: indice, section: 0)], with: .none)
                    //self.tableView.reloadData()
                    print("image loaded")
                })
            }
            print("after")
        })
    }
}

我想在后台模式下下载图片。我想使用应用程序进行跟踪,但 UI 已冻结,直到方法未在 reloadRows 中输入。

是否可以 运行 在真正的后台模式下,我可以使用该应用程序进行跟踪吗??

跟踪程序:

before
after
before
after
...
before
after
before
after
image yet dowload  --> here start UI frozen
image loaded
image yet dowload 
image yet dowload 
...
image yet dowload 
image yet dowload 
image loaded  
image loaded
...
image loaded
image loaded
image yet dowload ------> here UI is not frozen
image loaded

问题是由这一行引起的:let data = NSData(contentsOf: url!)NSData 的构造函数应该只用于读取本地 URL 的内容(iOS 设备上的文件路径),因为它是一个同步方法,因此如果你调用它从 URL 下载文件会阻塞 UI 很长时间。

我从未使用过 Firebase,但查看 documentation,在我看来,您使用错误的方法下载该文件。您应该使用 func getData(maxSize size: Int64, completion: @escaping (Data?, Error?) -> Void) -> StorageDownloadTask 而不是 func downloadURL(completion: @escaping (URL?, Error?) -> Void),因为正如文档所述,后者仅 "retrieves a long lived download URL with a revokable token",但不会下载URL 本身。

此外,您不应该在网络请求的完成处理程序中强制解包值。网络请求通常会因编程错误以外的原因而失败,但如果您不优雅地处理这些错误,您的程序就会崩溃。

你的问题出在这一行let data = NSData(contentsOf: url!),现在让我们看看下面苹果对这个方法的看法

Don't use this synchronous method to request network-based URLs. For network-based URLs, this method can block the current thread for tens of seconds on a slow network, resulting in a poor user experience, and in iOS, may cause your app to be terminated.

所以它明确指出此方法将阻止您的用户界面。