Brandon
Brandon

Reputation: 11

Why does my TableView only show the last image loaded in every cell? (swift)

The problem I have have at the moment is properly displaying images in a tableView cell. My images are saved to Firebase, and I can easily retrieve both images.

When I try to display each image in its own table view cell they quickly load both images and the end result is the last image displaying in both cells instead of two different images.

I believe the issue is either with my cellForRowAt IndexPath or how I am calling the data from Firebase.

This is my Main TableView View Controller

import UIKit
import Firebase
import FirebaseStorage
import FirebaseDatabase

class CardDesignViewController: UIViewController {

@IBOutlet weak var tableView: UITableView!
//passing a value to another page with thie var
var IdvalueTitle = ""
var db:Firestore!
//PropertiesCell2 is pointing to a swift file containing my dictionary for the outlets
var propertiesArray3 = [PropertiesCell2]()

override func viewDidLoad() {
    super.viewDidLoad()

    tableView.delegate = self
    tableView.dataSource = self


extension CardDesignViewController: UITableViewDataSource, UITableViewDelegate {


func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {

    return propertiesArray3.count
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

    let spot = propertiesArray3[indexPath.row]
    let cell = tableView.dequeueReusableCell(withIdentifier: "TableView2") as! TableView2


    cell.app? = "\(spot.templateOption)"

    cell.IDvalueHidden?.text = "\(spot.IDvalueHidden)"
    cell.templateOption.layer.cornerRadius = 12
    cell.templateOption.layer.masksToBounds = true

    return cell

}

I have put my outlets for the cells into a file called "TableView2". This is where I call the data for the images from Firebase in a func called getTemplates() and use that within "var app: String!"

import Foundation
import UIKit
import Firebase
import FirebaseDatabase
import FirebaseStorage

class TableView2: UITableViewCell {

@IBOutlet weak var templateOption: UIImageView!
@IBOutlet weak var IDvalueHidden: UILabel!

func  styleTheCells2(cells: Cell2) {

    templateOption.image = cells.templateOption
    IDvalueHidden.text = cells.IDvalueHidden
}
var app: String! {
    didSet {
        self.getTemplates()
    }
}
func getTemplates() {

    let db = Firestore.firestore()

    db.collection("Card Templates").getDocuments { (snapshot, err) in
        if err != nil {
            return
        } else {
            for document in (snapshot?.documents)! {
                if let picURL = document.data()["Template"] as? String {
                    let url = URL(string: picURL)
                    print(picURL)
                    DispatchQueue.global().async {
                        do{
                            let data = try Data(contentsOf: url!)
                            DispatchQueue.main.async {
                                self.templateOption.image = UIImage(data: data)
                            }
                        } catch {
                        }
                    }
                }
            }
        }
    }
}

I've attached a picture as well of the end result when I run this code. I get the same image in both cells however, when I look at the debug area I can see that both images were accessed twice.

This is my simulator when I run this code. Im looking to have two different images in the cells rather than the one picture in both:

enter image description here

My debugger shows both image urls being pulled twice consecutively and the last image pulled (the green image) shows in both cells:

enter image description here

Upvotes: 1

Views: 645

Answers (2)

Ashmit Bhui
Ashmit Bhui

Reputation: 36

You are fetching the images from Firebase Storage each time UITableViewCell is being presented via getTemplates() function

Since you have 2 images in Firebase, I am assuming 'propertiesArray3' has 2 elements in it.

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {

    return propertiesArray3.count
}

Each time it goes through the Firebase and prints out all the URLs in the db. As the numberOfRowsInSection is 2, the Image URL are being printed twice.

The for loop ends at the last element each time and sets the last URL as the image.

func getTemplates() {

let db = Firestore.firestore()

db.collection("Card Templates").getDocuments { (snapshot, err) in
    if err != nil {
        return
    } else {
        for document in (snapshot?.documents)! {
            if let picURL = document.data()["Template"] as? String {
                let url = URL(string: picURL)
                print(picURL)
                DispatchQueue.global().async {
                    do{
                        let data = try Data(contentsOf: url!)
                        DispatchQueue.main.async {
                            self.templateOption.image = UIImage(data: data)
                        }
                    } catch {
                    }
                }
            }
        }
    }
}

Hope it helps

For a basic approach to start with, you can try something like this - Declare an array to store the URL

var urlArray: [URL] = []

Fetch the URLs in viewDidLoad()

let db = Firestore.firestore()
db.collection("Card Templates").getDocuments { (snapshot, err) in
    if err != nil {
        return
    } else {
        for document in (snapshot?.documents)! {

            if let picURL = document.data()["Template"] as? String {
                let url = URL(string: picURL)
                // ADD ALL THE URLs TO THE NEW ARRAY
                urlArray.append(url)                    
            }
        }
        tableView.reloadData()
    }
}

Remove getTemplates() from UITableViewCell

Edit the tableView Delegate

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {

    return urlArray.count
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

    let spot = propertiesArray3[indexPath.row]
    let cell = tableView.dequeueReusableCell(withIdentifier: "TableView2") as! TableView2

    let url = urlArray[indexPath.row]
    do{
        let data = try Data(contentsOf: url!)
        DispatchQueue.main.async {
            cell.templateOption.image = UIImage(data: data)
        }
      } catch {
      }


    cell.app? = "\(spot.templateOption)"

    cell.IDvalueHidden?.text = "\(spot.IDvalueHidden)"
    cell.templateOption.layer.cornerRadius = 12
    cell.templateOption.layer.masksToBounds = true

    return cell

} 

Upvotes: 1

Sebastian
Sebastian

Reputation: 44

You most clear content based Views of cell in prepareForReuse function

override func prepareForReuse() {
        super.prepareForReuse()

        // remove image from imageView
        templateOption.image = nil
    } 

Upvotes: 0

Related Questions