我正在下载存储在Firebase中的图像,并将它们放在一个数组中。 但是,当我检索它们并将其显示在表格视图中时,图像似乎是混乱的,并且每次都怪异地不一致。有人知道如何固定代码吗?
override func viewDidLoad() {
super.viewDidLoad()
ref = Database.database().reference()
retrieveData()
retrieveImage()
}
func retrieveImage(){
let userID = Auth.auth().currentUser?.uid
ref.child("Images").observeSingleEvent(of: .value, with: { (snapshot) in
let userImage = snapshot.value as? NSDictionary
let imageURLArray = userImage?.allKeys
if userImage != nil{
for index in 0...userImage!.count-1{
let imageProfile = userImage![imageURLArray?[index]] as? NSDictionary
let imageURL = imageProfile!["url"]
let usernameDB = imageProfile!["username"]
let timeCreatedDB = imageProfile!["timeCreated"] as? Double
let date = NSDate(timeIntervalSince1970: timeCreatedDB!)
let dayTimePeriodFormatter = DateFormatter()
dayTimePeriodFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
let dateString = dayTimePeriodFormatter.string(from: date as Date)
let storageRef = Storage.storage().reference(forURL: imageURL as! String)
self.usernames.insert(usernameDB as! String, at: 0)
self.timesCreated.insert(dateString, at: 0)
storageRef.getData(maxSize: 1 * 1024 * 1024) { data, error in
if let error = error {
print(error.localizedDescription)
} else {
let image = UIImage(data: data!)
self.images.insert(image!, at: 0)
self.tableView.reloadData()
}
}
}
}
}) { (error) in
print(error.localizedDescription)
}
}
答案 0 :(得分:0)
问题是,要在循环内获取图像的调用会异步返回图像,因此,尽管您可以按特定顺序请求所有图像,但由于文件的变化,不能保证它们按该顺序返回尺寸(较小的图像可能会更快返回)。您还需要在每次获取图像后重新加载表,这不会导致问题,但是我建议您采用这种设计;只需在所有数据都掌握之后再加载表即可。
要解决您的问题,应在所有图像均已异步下载后使用调度组通知您。然后您可以对数组进行排序并加载表格。这是使用调度组的常见地方-包含异步调用的内部循环。在循环外声明调度组,在每个异步调用之前进入该组,并在每次异步返回之后离开该组。然后,调度组调用其完成块,在其中对数组进行排序并加载表。
func retrieveImage(){
let userID = Auth.auth().currentUser?.uid
ref.child("Images").observeSingleEvent(of: .value, with: { (snapshot) in
let userImage = snapshot.value as? NSDictionary
let imageURLArray = userImage?.allKeys
if userImage != nil{
let dispatchGroup = DispatchGroup() // create dispatch group outside of the loop
for index in 0...userImage!.count-1{
let imageProfile = userImage![imageURLArray?[index]] as? NSDictionary
let imageURL = imageProfile!["url"]
let usernameDB = imageProfile!["username"]
let timeCreatedDB = imageProfile!["timeCreated"] as? Double
let date = NSDate(timeIntervalSince1970: timeCreatedDB!)
let dayTimePeriodFormatter = DateFormatter()
dayTimePeriodFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
let dateString = dayTimePeriodFormatter.string(from: date as Date)
let storageRef = Storage.storage().reference(forURL: imageURL as! String)
self.usernames.insert(usernameDB as! String, at: 0)
self.timesCreated.insert(dateString, at: 0)
dispatchGroup.enter() // enter this group before async call
storageRef.getData(maxSize: 1 * 1024 * 1024) { data, error in
if let error = error {
print(error.localizedDescription)
} else {
let image = UIImage(data: data!)
self.images.insert(image!, at: 0)
//self.tableView.reloadData() don't reload here
}
dispatchGroup.leave() // leave this group after async return
}
}
// this is called after all of the async calls in the loop returned
// it puts you on the main thread
dispatchGroup.notify(queue: .main, execute: {
self.tableView.reloadData() // load table
})
}
}) { (error) in
print(error.localizedDescription)
}
}
上面的代码不包含排序机制,因为这比我想做的要多一些编码,但是执行很简单。为了使图像保持相同的顺序,您可以执行许多操作,其中之一是枚举循环,获取每次循环迭代的计数并将其附加到图像上,然后按照该数字对数组进行排序,然后再进行操作。加载表格。
for (count, image) in images.enumerated() {
// take the count and attach it to each image
// the easiest way I think is to create a custom object
// that contains the image and the count
}
// and then in your dispatch group completion handler...
dispatchGroup.notify(queue: .main, execute: {
// sort the images by their enumerated count before loading the table
imagesArray.sort { $0.thatCount < $1.thatCount }
DispatchQueue.main.async {
self.tableView.reloadData() // load the table
}
})