Search code examples
uicollectionviewuicollectionviewcelltvos

UICollectionView wrong image displayed


I've found a couple of posts about issues with UICollectionView and iwrong images but all of them have one common - people try to download image in cellForItemAt method. I already have proper image in my app bundle and simply use UIImage(named:) method to set it to UICollectionViewCell. However I still get wrong images. Could anyone help me?

    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    return liveChannels.count()
}

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "ChannelButtonViewCell", for: indexPath) as! ChannelButtonViewCell


        let current = liveChannels.channels[indexPath.row]
        let currentProgram = current.currentProgram()

        let channelKey = current.channel?.channelKey
        let programDetail = currentProgram?.name

        if let currentProgress = currentProgram?.progress() {
            cell.progressView.setProgress(currentProgress, animated: true)
        }

        print("\(channelKey) - \(current.channel!.logoName)")
        cell.imageName = current.channel!.logoName
        cell.channelTitleLabel.text = channelKey
        cell.channelDetailLabel.text = programDetail

        cell.channelButton.addTarget(self, action: #selector(ChannelsViewController.pressed(_:)), for: .primaryActionTriggered)
        return cell
    }

I'm printing channelKey and logoName to console to be sure that the proper image is stored inside of liveChannels.channels structure. (THey are correct indeed).

This is my cell:

class ChannelButtonViewCell: UICollectionViewCell {

    @IBOutlet weak var progressView: UIProgressView!
    @IBOutlet weak var channelButton: ChannelButton!
    @IBOutlet weak var channelDetailLabel: UILabel!
    @IBOutlet weak var channelTitleLabel: UILabel!
    @IBOutlet weak var channelImageView: UIImageView!
    var imageName: String?

    override func prepareForReuse() {

        channelImageView.image = nil

        super.prepareForReuse()
    }

    override func draw(_ rect: CGRect) {
        if (self.isSelected) {
            if let imageName  = imageName {
                channelImageView.image = UIImage(named: imageName)
            }

        } else {
            if let imageName  = imageName {
                channelImageView.image = UIImage(named: imageName.appending("_grey"))
            }

        }
    }
}

Solution

  • 1) You should override func draw(_ rect: CGRect) in very rare cases and your case is definitely not the one.

    2) To ensure you load and change image exactly when you assign cell's var imageName: String? you could use Swift's didSet

    3) To ensure your image updates when selection state changes you could use didSet as well.

    you could end up removing func draw at all and adding didSet observers like this:

    class ChannelButtonViewCell: UICollectionViewCell {
    
        @IBOutlet weak var progressView: UIProgressView!
        @IBOutlet weak var channelButton: ChannelButton!
        @IBOutlet weak var channelDetailLabel: UILabel!
        @IBOutlet weak var channelTitleLabel: UILabel!
        @IBOutlet weak var channelImageView: UIImageView!
        var imageName: String? {
            didSet {
                updateImage()
            }
        }
    
        override var isSelected: Bool {
            didSet {
                updateImage()
            }
        }
    
        override func prepareForReuse() {
            channelImageView.image = nil
            super.prepareForReuse()
        }
    
        func updateImage() {
            guard let imageName = self.imageName else { return }
            if (self.isSelected) {
                channelImageView.image = UIImage(named: imageName)
            } else {
                channelImageView.image = UIImage(named: imageName.appending("_grey"))
            }
        }
    
    }
    

    If this solution doesn't solve your problem try set breakpoint inside of func draw() and check when it is called and what value stored in var imageName