Странный Несогласованный просмотр таблицы Swift 4 - PullRequest
0 голосов
/ 08 декабря 2018

Я загружаю изображения, хранящиеся в 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)
    }

}

1 Ответ

0 голосов
/ 08 декабря 2018

Проблема в том, что вызов для получения изображения внутри цикла возвращает изображение асинхронно, и поэтому, хотя вы можете запросить все изображения в определенном порядке, они не гарантированно возвращаются в этом порядке, главным образом из-за изменяющегося файла.размеры (меньшие изображения, скорее всего, вернутся раньше).Вы также перезагружаете таблицу после каждого получения изображения, что не усугубляет вашу проблему, но дизайн, который я рекомендовал бы против;просто загрузите таблицу один раз после того, как все данные будут в наличии.

Чтобы решить вашу проблему, вы должны использовать группу рассылки, чтобы уведомить вас, когда все изображения были загружены асинхронно;затем вы можете отсортировать массив и загрузить таблицу.Это обычное место для использования групп диспетчеризации - внутри циклов, которые содержат асинхронные вызовы.Объявите группу диспетчеризации вне цикла, введите группу перед каждым асинхронным вызовом и покиньте эту группу после каждого асинхронного возврата.Затем группа диспетчеризации вызывает свой блок завершения, где вы сортируете массив и загружаете таблицу.

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
    }

})
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...