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.
所以它明确指出此方法将阻止您的用户界面。
我对这个方法有疑问:
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.
所以它明确指出此方法将阻止您的用户界面。