0

Problem: See video. I'm downloading the images from Firebase storage and displaying on the table view cell. After I build the app, the images don't show up in the first cells of the table view. Upon scrolling down and back up, I can see images in first cells of the table view.

I consulted this question (clearing app data & cache of simulator didn't work) and this question (different problem b/c they're downloading image from url). I read this about using a placeholder image, but I'm not sure if it's applicable because I'm not using SDWebImage and my cell uses my own companyImage UIImageView and not the imageView that comes with UITableView cell.

Code:

Company View Controller:

class CompanyViewController: UIViewController, UISearchBarDelegate, UIScrollViewDelegate, UITableViewDelegate, UITableViewDataSource {

override func viewDidLoad() {
    super.viewDidLoad()
    companyTableView.register(CompanyTableViewCell.self, forCellReuseIdentifier: "CompanyTableViewCell")
    companyTableView.register(UINib(nibName: "CompanyTableViewCell", bundle: nil), forCellReuseIdentifier: "CompanyTableViewCell")
    loadData()
}

func loadData() {
        databaseHandle = databaseRef?.child("companies").observe(.value, with: { (snapshot) in
            for item in snapshot.children.allObjects as! [FIRDataSnapshot] {
                let company = Company()
                let id = item.childSnapshot(forPath: Property.id.rawValue).value as! String
                let imageName = id + ".png"
                let imageRef = self.storageRef?.child(imageName)
                imageRef?.data(withMaxSize: 1 * 1024 * 1024) { data, error in
                    if let error = error {
                        print((error as Error).localizedDescription)
                    } else if let data = data {
                        // Data for "images/companyid.png" is returned
                        company.image = UIImage(data: data)
                    }
                }
                self.informationStateController?.addCompany(company: company)
            }
            DispatchQueue.main.async {
                self.companyTableView.reloadData()
            }
        })
    }

 func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
    {
        let company = (self.informationStateController?.companies[indexPath.row])!
        let customCell = tableView.dequeueReusableCell(withIdentifier: CompanyTableViewCell.identifier) as! CompanyTableViewCell
                customCell.companyImage.image = company.image
        return customCell
    }
}

Company Table View Cell

class CompanyTableViewCell: UITableViewCell {
    
    @IBOutlet weak var companyImage: UIImageView!
    
    override func awakeFromNib() {
        super.awakeFromNib()
        companyImage.contentMode = .scaleAspectFit
     }
}
Community
  • 1
  • 1
14wml
  • 4,048
  • 11
  • 49
  • 97
  • Welcome back. Did you at least try using a placeholder image? If that solution works for an `SDWebImage`, it should still be applicable here. I'd at least recommend trying it to see what happens. – Pierce Jan 14 '17 at 20:07
  • Have you tried debugging whether `company.image` returns anything in the `tableView:cellForRowAt:` function for the first screen load? – silicon_valley Jan 14 '17 at 20:21
  • Oh okay, I just did that, for the first screen loads, all seven cells' images returns `nil`, but when I scroll down & scroll back up, I get `Optional(, {1998, 496})`, `Optional(, {646, 218})`, etc – 14wml Jan 14 '17 at 20:28
  • Have you tried what the answer said on the question you linked about just deleting the app and re-installing it? – Pierce Jan 14 '17 at 20:47
  • BTW If you are loading your cell from a `.xib` file, delete that first `register` line `companyTableView.register(CompanyTableViewCell.self, forCellReuseIdentifier: "CompanyTableViewCell")`. You only need the second one – Pierce Jan 14 '17 at 20:48
  • yupp I did both of those things and it didnt change anything – 14wml Jan 14 '17 at 20:50

1 Answers1

0

I finally found a pretty decent solution to the load image issue (but not the memory issue). I used this question.

Before, I was returning the company object before the images had been downloaded. Instead, in my updated method, I assign the image to the company object on the main queue and since that's when I know the company object has an image, I also reload the table view.

Note: The solution isn't perfect because I do notice that there's a bit of wait to get the images all loaded when I first open this view controller, but it's the best solution I've found so far.

Updated Code

func loadData() {
    databaseHandle = databaseRef?.child("companies").observe(.value, with: { (snapshot) in
        for item in snapshot.children.allObjects as! [FIRDataSnapshot] {
            let company = Company()
            let id = item.childSnapshot(forPath: Property.id.rawValue).value as! String
            let imageName = id + ".png"
            let imageRef = self.storageRef?.child(imageName)
            imageRef?.data(withMaxSize: 1 * 1024 * 1024) { data, error in
                if let error = error {
                    print((error as Error).localizedDescription)
                } else if let data = data {
                    DispatchQueue.main.async { //UPDATED PART OF CODE STARTS HERE
                        company.image = UIImage(data: data)
                        self.companyTableView.reloadData()
                    } //UPDATED PART OF CODE ENDS HERE

                }
            }
            self.informationStateController?.addCompany(company: company)
        }
    })
}
Community
  • 1
  • 1
14wml
  • 4,048
  • 11
  • 49
  • 97
  • If another person stumbles across this answer, if your issue it not a simple race condition with your loading, it can also be due to auto layout and your constraints and the display system calculating that your view is not visible on screen. try adjusting your auto layout constraints if you know your issue is not due to a race condition. – John Nov 12 '18 at 05:36