奇怪的不一致的表视图Swift 4



我正在下载存储在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)
}
}

问题是,在循环中获取图像的调用异步返回图像,因此,虽然您可以按特定顺序请求所有图像,但它们不能保证按该顺序返回,主要是因为文件大小不同(较小的图像可能会更快返回(。在每次获得图像后,您还需要重新加载表格,这不会导致您的问题,但我建议不要这样做;只需在所有数据都在手之后加载一次表。

要解决您的问题,您应该使用调度组在异步下载所有图像时通知您;然后可以对数组进行排序并加载表。这是一个常见的使用调度组的地方——在包含异步调用的循环中。在循环之外声明分派组,在每次异步调用之前输入该组,并在每次异步返回之后离开该组。然后调度组调用它的完成块,在那里对数组进行排序并加载表。

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

最新更新