奇怪的不一致表视图Swift 4

时间:2018-12-08 08:27:04

标签: swift firebase uitableview firebase-realtime-database

我正在下载存储在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 :(得分: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
    }

})