4

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
    }

}
maxwell
  • 3,788
  • 6
  • 26
  • 40
Nikita Goncharov
  • 173
  • 2
  • 13
  • 5
    Don't bypass cell reuse, cache the images locally once they've been downloaded. – rmaddy Dec 14 '18 at 16:42
  • Why not? There is not much point to keep reusing , cause i have only a few cells (not tons of) and i have to keep locally downloaded images anyway. So why don't store it into cell? Or i don't understand smth? – Nikita Goncharov Dec 14 '18 at 16:52
  • CollectionView is designed to reuse cells, that’s the basis and the most important point of a collectionView. I think you are confusing what exactly reuse means, it just means that if cells are offscreen, the current ones are “reused” to set them up, instead of creating and deleting them all the time. – Galo Torres Sevilla Dec 14 '18 at 17:49
  • There are frameworks like SDWebImage and Kingfisher that can take care of the image caching and reuse for you. You are confusing image caching with cell reuse, while you can achieve the first by turning off the second, you should learn the right way to do things – Paulw11 Dec 14 '18 at 20:54
  • @GaloTorresSevilla, is there a way to control when a cell should be reused? Sometimes I want the cells to show outside of the visible bounds of the collection view. – Winston Du May 07 '22 at 02:20

2 Answers2

2

Just create, fill and return new cell object in cellForItemAt instead of dequeueing it, but it's not a qood practice and you shouldn't do that.

0

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.

Omar Masri
  • 349
  • 1
  • 8