iosswiftuicollectionviewuicollectionviewcellreuseidentifier

How to NOT reuse cells in UICollectionView - Swift


I have UICollectionView in a cell of UITableView. This UICollectionView displays user's profile photos. There are only a few items there (let's assume 10 photos is a maximum).

So, I do not want to reload images from backend every time cell reusing. It's inconvenient and unfriendly UX. Therefore, I want to create 10 cells, load images into them and show.

But I don't know how to create (instead of dequeuing) new custom cells within "cellForItem" method of UICollectionView. Or how to forbid reusing.

I'm a kind of newbie in programming, so I would be glad if you explained me that in simple words and most detailed. Thank you.

Here is my code:

Setting CollectinView (uploading random local photos in testing purpose):

extension PhotosTableViewCell: UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {

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

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {

        if indexPath.row == 0 {
            let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "AddPhotoCollectionViewCell", for: indexPath)
            return cell
        } else {
            var cell = collectionView.dequeueReusableCell(withReuseIdentifier: "PhotoCollectionViewCell", for: indexPath) as! PhotoCollectionViewCell
            cell.photo = UIImage(named: "Photo\(Int.random(in: 1...8))") ?? UIImage(named: "defaultPhoto")
            cell.layer.cornerRadius = 10

            return cell
        }
    }

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {

        let height = collectionView.frame.height
        let width = (height / 16.0) * 10.0

        return CGSize(width: width, height: height)
    }

}

My custom PhotoCollectionViewCell:

class PhotoCollectionViewCell: UICollectionViewCell {

    @IBOutlet weak var imageView: UIImageView!
    @IBOutlet weak var heightConstraint: NSLayoutConstraint!
    @IBOutlet weak var widthConstraint: NSLayoutConstraint!

    var photo: UIImage! {
        didSet {
            // simulate networking delay
            perform(#selector(setImageView), with: nil, afterDelay: Double.random(in: 0.2...1))

            // setImageView()
        }
    }

    override func awakeFromNib() {
        super.awakeFromNib()
        // Initialization code
    }

    @objc private func setImageView() {
        let cellHeight = self.frame.height
        let cellWidth = self.frame.width
        let cellRatio = cellHeight / cellWidth

        let photoRatio = photo.size.height / photo.size.width

        var estimatedWidth = cellWidth
        var estimatedHeight = cellHeight

        if photoRatio > cellRatio {
            estimatedWidth = cellWidth
            estimatedHeight = cellWidth * photoRatio
        } else {
            estimatedHeight = cellHeight
            estimatedWidth = cellHeight / photoRatio
        }

        widthConstraint.constant = estimatedWidth
        heightConstraint.constant = estimatedHeight
        imageView.image = photo
    }

    override func prepareForReuse() {
        imageView.image = nil
    }

}

Solution

  • You need to create new cell each time and assign the value to it. Although this is very dangerous thing to do and can cause your app to take so much memory over use your app will use more power and make the device slower.

    Instead I suggest that you save your data into a Collection and to keep reusing it as you go.