Проблема в том, что вызов для получения изображения внутри цикла возвращает изображение асинхронно, и поэтому, хотя вы можете запросить все изображения в определенном порядке, они не гарантированно возвращаются в этом порядке, главным образом из-за изменяющегося файла.размеры (меньшие изображения, скорее всего, вернутся раньше).Вы также перезагружаете таблицу после каждого получения изображения, что не усугубляет вашу проблему, но дизайн, который я рекомендовал бы против;просто загрузите таблицу один раз после того, как все данные будут в наличии.
Чтобы решить вашу проблему, вы должны использовать группу рассылки, чтобы уведомить вас, когда все изображения были загружены асинхронно;затем вы можете отсортировать массив и загрузить таблицу.Это обычное место для использования групп диспетчеризации - внутри циклов, которые содержат асинхронные вызовы.Объявите группу диспетчеризации вне цикла, введите группу перед каждым асинхронным вызовом и покиньте эту группу после каждого асинхронного возврата.Затем группа диспетчеризации вызывает свой блок завершения, где вы сортируете массив и загружаете таблицу.
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
}
})