简体   繁体   中英

UITableView's cell is flickering from good to wrong image and fix after scrolling

I'm trying to fill UITableView's Cell with datas from my firestore database.

For some reasons, when i switch to the app's tab containing my tableview, i can see the good image for half a second and then it flickers to the one of the preceding cell.

Then, if i scroll down and goes back up, the good image is back but if i scroll up and down to fast, wrong images get called again.

To retrieve my datas and populate the cells i do like this:

In my class file

Retrieve the "main items" (This one works just fine)

  • Main item's ID
  • sub item 1's ID
  • sub item 2's ID

Retrieve the details of "the sub items"

  • sub item's ID
  • sub item's IMG URL
  • ...

This code also include "useless" code used for testing purpose, in a hope of finding the solution..

    var groupNom:String = ""
    var groupStyles:String = ""
    var groupHeaderImg = [StorageReference]()
    var groupIconeImg = [StorageReference]()
    var videosArrayed = [String]()
    var groupIconeURL:String = ""

    func getGroupDetails(Did: String, completion: @escaping (_ message: String) -> Void) {

        let db = Firestore.firestore()
        let storage = Storage.storage()

        let docRef = db.collection("groups").document(Did)

        docRef.getDocument { (document, error) in
            if let document = document, document.exists {

                self.groupNom = document.get("nom") as! String
                self.groupStyles = document.get("styles") as! String
                let icone_img = document.get("icone_img") as! String

                self.groupIconeImg.removeAll()
                self.groupIconeImg.append(storage.reference(forURL: self.StorageRefRoot + "/groups/" + document.documentID + "/icones/" + icone_img + ".png"))
                //self.groupIconeURL.removeAll()
                self.groupIconeURL = self.StorageRefRoot + "/groups/" + document.documentID + "/icones/" + icone_img + ".png"
                //print("id: \(Did) array d'icone: \(self.groupIconeImg)")
                self.groupHeaderImg.append(storage.reference(forURL:"\(self.StorageRefRoot)/groups/\(Did)/headers/\(document.get("header_img") as! String).png"))

                let stylesNSArray = document.get("styles_ids") as! Array<Any>
                let stylesArrayed: [String] = stylesNSArray.compactMap({ $0 as? String })


                var tempGroupStyles = ""


                for i in stylesArrayed.indices {

                    let styleDocRef = db.collection("styles_groupes").document(stylesArrayed[i])
                    styleDocRef.getDocument { (document, error) in
                        if let document = document, document.exists {
                            //tempBarStyles = ""
                            if i < stylesArrayed.count-1 { // Si c'est le dernier element, on n'ajoute pas de virgule
                                tempGroupStyles = "\(tempGroupStyles)\(document.get("nom") as! String), "
                            } else {
                                tempGroupStyles = "\(tempGroupStyles)\(document.get("nom") as! String)"
                                //print("barstyles = \(tempGroupStyles)")

                            }

                            if i == stylesArrayed.count-1 {
                                self.groupStyles = tempGroupStyles
                            }

                        } else {
                            print("style to be decrypted do not exist")
                            return
                        }
                        completion("done")
                    }
                }

                let videosNSArray = document.get("videos_yt_ids") as! Array<Any>
                self.videosArrayed = videosNSArray.compactMap({ $0 as? String })



            } else {
                print("Groups details does not exist")
                return
            }
            completion("done")
        }

    }

In my ViewController

  • Return as many cells as there are Main items by running the Main items' class (This one works just fine)
  • For each Main items, retrieve the details of the sub items' ID by running the sub items' class

This code also include "useless" code used for testing purpose, in a hope of finding the solution..

    var feedAbos = abo()
    var feedBars = bar()
    var feedGroupes = group()

    @IBOutlet weak var abosCollectionView: UICollectionView!
    @IBOutlet weak var aboFeedTableView: UITableView!

    override func viewDidLoad() {
        super.viewDidLoad()


    }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated) // No need for semicolon

        if Auth.auth().currentUser != nil {
            //print("l'utilisateur en cours est: \(String(describing: Auth.auth().currentUser?.uid))")

            feedAbos = abo()
            feedAbos.getAbosFeed(uid: Auth.auth().currentUser!.uid, completion: { message in
                self.aboFeedTableView.reloadData()
            })
        } else {
            showLoginVC(viewToPresent: self, isModale: true)
        }



    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return feedAbos.feedLivesID.count
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView
            .dequeueReusableCell(withIdentifier: "abosLivesFeedCell", for: indexPath as IndexPath) as! abosLivesFeedCell


        self.feedGroupes.getGroupDetails(Did: self.feedAbos.feedGroupesID[indexPath.row], completion: { message in
            if self.feedGroupes.groupIconeURL != "" {
                            cell.liveFeedGroupeImage.sd_setImage(with: URL(string: self.feedGroupes.groupIconeURL), placeholderImage: UIImage(named: "PLACEHOLDER1"))
            } else {
                cell.liveFeedGroupeImage.image = UIImage(named: "PLACEHOLDER1")
            }

            cell.liveFeedGroupeImage.layer.cornerRadius = 5
            cell.liveFeedGroupeNomLabel?.text = self.feedAbos.feedGroupesID[indexPath.row]

        })
        cell.liveFeedDateLabel?.text = self.feedAbos.feedLivesDates[indexPath.row]
        return cell
    }

class abosLivesFeedCell: UITableViewCell {

    @IBOutlet weak var liveFeedBarImage: UIImageView!
    @IBOutlet weak var liveFeedGroupeImage: UIImageView!
    @IBOutlet weak var liveFeedGroupeNomLabel: UILabel!
    @IBOutlet weak var liveFeedDateLabel: UILabel!
    @IBOutlet weak var liveFeedBarNomLabel: UILabel!

    override func prepareForReuse() {
        super.prepareForReuse()
        self.liveFeedGroupeImage.image = nil
    }
}

I think it has to do with the fact i use async data downloading. I'm thinking that maybe it has to do with the way i handle completion of my firestore classes... I also read about dispatching methods but i never used that yet.

I am pretty lost right know as it may just be something i don't know as i am definitely not a professional coder:)

Hope someone can point me in the right direction or show me where i did that stupid and very visible mistake;D

Thank you everyone !

Ok, here is what i just did to make it work. I don't think that it's the right way but it seems to work.. so..

In my ViewController i check if the Sub item's ID from the Main items' class is the same as the one retrieved from the sub items' class. If so, i load the sub items' class image into my cell.

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView
            .dequeueReusableCell(withIdentifier: "abosLivesFeedCell", for: indexPath as IndexPath) as! abosLivesFeedCell
        cell.liveFeedGroupeImage.image = UIImage(named: "PLACEHOLDER1")

        self.feedGroupes.getGroupDetails(Did: self.feedAbos.feedGroupesID[indexPath.row], completion: { message in
            if self.feedGroupes.groupID == self.feedAbos.feedGroupesID[indexPath.row] {
                            cell.liveFeedGroupeImage.sd_setImage(with: URL(string: self.feedGroupes.groupIconeURL), placeholderImage: UIImage(named: "PLACEHOLDER1"))
            } else {

            }

            cell.liveFeedGroupeImage.layer.cornerRadius = 5
            cell.liveFeedGroupeNomLabel?.text = self.feedAbos.feedGroupesID[indexPath.row]

        })
        cell.liveFeedDateLabel?.text = self.feedAbos.feedLivesDates[indexPath.row]
        return cell
    }

Hopefully one day i'll find where i am wrong. if so, i'll update the answer!

thanks everyone.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM