0

I noticed that my collectionview was taking up to 50 MB of memory per cell (obviously a problem) and after some testing, it seems to be that it is my custom UICollectionViewCell itself. The cell is supposed to look like this:

enter image description here

This is the cell's class. My guess is that I'm trying to make it too fancy and I'm using up too many resources displaying stuff.

import UIKit

class UserCell: UICollectionViewCell {

    let profilePicImageView: AsyncImageView = {
        let imageView = AsyncImageView()
        imageView.layer.masksToBounds = true
        imageView.layer.borderWidth = 1
        imageView.layer.borderColor = UIColor(r: 60, g: 151, b: 138).cgColor
        return imageView
    }()

    let usernameLabel: UILabel = {
        let label = UILabel()
        label.textColor = .white
        label.alpha = 0.9
        label.font = label.font.withSize(15)
        label.text = ""
        label.translatesAutoresizingMaskIntoConstraints = false
        return label
    }()

    let rankLabel: UILabel = {
        let label = UILabel()
        label.textColor = UIColor(r: 60, g: 151, b: 138)
        label.font = label.font.withSize(15)
        label.sizeToFit()
        label.translatesAutoresizingMaskIntoConstraints = false
        return label
    }()

    let regionLabel: UILabel = {
        let label = UILabel()
        label.textColor = .white
        label.textAlignment = .center
        label.font = label.font.withSize(10)
        label.sizeToFit()
        label.translatesAutoresizingMaskIntoConstraints = false
        return label
    }()

    let platformLabel: UILabel = {
        let label = UILabel()
        label.textAlignment = .center
        label.textColor = .white
        label.font = label.font.withSize(10)
        label.sizeToFit()
        label.translatesAutoresizingMaskIntoConstraints = false
        return label
    }()

    let connectButton: UIButton = {
        let button = UIButton()
        button.backgroundColor = UIColor(r: 28, g: 36, b: 49)
        button.setTitle("Connect", for: .normal)
        button.setTitleColor(.white, for: .normal)
        button.backgroundColor = .black
        button.layer.cornerRadius = 5
        button.layer.masksToBounds = true
        button.layer.borderColor = UIColor(r: 60, g: 151, b: 138).cgColor
        button.layer.borderWidth = 1
        button.translatesAutoresizingMaskIntoConstraints = false
        return button
    }()

    let ratingLabel: UILabel = {
        let label = UILabel()
        label.text = "5"
        label.textColor = .white
        label.font = label.font.withSize(12)
        label.sizeToFit()
        label.translatesAutoresizingMaskIntoConstraints = false
        return label
    }()

    let cellView: UIView = {
        let view = UIView()
        view.backgroundColor = UIColor(r: 25, g: 30, b: 38)
        view.layer.borderColor = UIColor(r: 60, g: 151, b: 138).cgColor
        view.layer.borderWidth = 1
        view.layer.cornerRadius = 10
        view.layer.masksToBounds = true
        return view
    }()

    let ratingBackground: UIImageView = {
        let imageView = UIImageView()
        imageView.image = UIImage(named: "ratingBackground")
        imageView.alpha = 0.2
        return imageView
    }()

    let regionView: UIView = {
        let view = UIView()
        view.backgroundColor = .black
        view.translatesAutoresizingMaskIntoConstraints = false
        view.layer.masksToBounds = true
        view.layer.borderWidth = 0.5
        view.layer.borderColor = UIColor(r: 60, g: 151, b: 138).cgColor
        return view
    }()

    let micImageView: AsyncImageView = {
        let imageView = AsyncImageView()
        imageView.layer.masksToBounds = true
        imageView.layer.borderWidth = 0.5
        imageView.layer.borderColor = UIColor(r: 60, g: 151, b: 138).cgColor
        imageView.image = UIImage(named: "mic")
        imageView.translatesAutoresizingMaskIntoConstraints = false
        imageView.backgroundColor = .black
        return imageView
    }()

    let ratingStar: UIImageView = {
        let imageView = UIImageView()
        imageView.image = UIImage(named: "star")
        imageView.translatesAutoresizingMaskIntoConstraints = false
        return imageView
    }()

    let platformView: UIView = {
        let view = UIView()
        view.backgroundColor = .black
        view.translatesAutoresizingMaskIntoConstraints = false
        view.layer.masksToBounds = true
        view.layer.borderWidth = 0.5
        view.layer.borderColor = UIColor(r: 60, g: 151, b: 138).cgColor
        return view
    }()

    let separatorView: UIView = {
        let view = UIView()
        view.backgroundColor = UIColor.init(r: 140, g: 140, b: 140, a: 0.1)
        return view
    }()

    override init(frame: CGRect) {
        super.init(frame: frame)

        profilePicImageView.layer.cornerRadius = frame.height / 5
        regionView.layer.cornerRadius = frame.height / 10
        micImageView.layer.cornerRadius = frame.height / 10
        platformView.layer.cornerRadius = frame.height / 10

        addSubview(cellView)

        cellView.addSubview(ratingBackground)
        cellView.addSubview(profilePicImageView)
        cellView.addSubview(usernameLabel)
        cellView.addSubview(rankLabel)
        cellView.addSubview(micImageView)
        cellView.addSubview(regionView)
        cellView.addSubview(regionLabel)
        cellView.addSubview(ratingStar)
        cellView.addSubview(ratingLabel)
        cellView.addSubview(platformView)
        cellView.addSubview(platformLabel)
        cellView.addSubview(separatorView)
        cellView.addSubview(connectButton)

        cellView.anchor(topAnchor, left: leftAnchor, bottom: bottomAnchor, right: rightAnchor, topConstant: frame.height * 0.1, leftConstant: frame.height * 0.15, bottomConstant: 0, rightConstant: frame.height * 0.15, widthConstant: 0, heightConstant: 0)
        profilePicImageView.anchor(cellView.topAnchor, left: cellView.leftAnchor, bottom: nil, right: nil, topConstant: frame.height * 0.1, leftConstant: frame.height * 0.1, bottomConstant: 0, rightConstant: 0, widthConstant: frame.height / 2.5, heightConstant: frame.height / 2.5)
        ratingBackground.anchor(profilePicImageView.centerYAnchor, left: profilePicImageView.leftAnchor, bottom: cellView.bottomAnchor, right: profilePicImageView.rightAnchor, topConstant: 0, leftConstant: frame.height * 0.02, bottomConstant: frame.height * 0.1, rightConstant: frame.height * 0.02, widthConstant: 0, heightConstant: 0)
        separatorView.anchor(usernameLabel.bottomAnchor, left: usernameLabel.leftAnchor, bottom: nil, right: cellView.rightAnchor, topConstant: 5, leftConstant: 0, bottomConstant: 0, rightConstant: 0, widthConstant: 0, heightConstant: 0.5)

        usernameLabel.centerYAnchor.constraint(equalTo: profilePicImageView.centerYAnchor).isActive = true
        usernameLabel.leftAnchor.constraint(equalTo: profilePicImageView.rightAnchor, constant: frame.height * 0.1).isActive = true
        usernameLabel.heightAnchor.constraint(equalTo: profilePicImageView.heightAnchor, multiplier: 0.5).isActive = true
        usernameLabel.widthAnchor.constraint(equalTo: cellView.widthAnchor, multiplier: 0.4).isActive = true

        micImageView.centerYAnchor.constraint(equalTo: usernameLabel.centerYAnchor).isActive = true
        micImageView.rightAnchor.constraint(equalTo: cellView.rightAnchor, constant: -10).isActive = true
        micImageView.heightAnchor.constraint(equalTo: usernameLabel.heightAnchor).isActive = true
        micImageView.widthAnchor.constraint(equalTo: usernameLabel.heightAnchor).isActive = true

        rankLabel.leftAnchor.constraint(equalTo: usernameLabel.leftAnchor).isActive = true
        rankLabel.centerYAnchor.constraint(equalTo: connectButton.centerYAnchor).isActive = true

        ratingStar.leftAnchor.constraint(equalTo: ratingBackground.centerXAnchor, constant: 2).isActive = true
        ratingStar.centerYAnchor.constraint(equalTo: ratingBackground.centerYAnchor, constant: 5).isActive = true
        ratingStar.heightAnchor.constraint(equalTo: ratingBackground.widthAnchor, multiplier: 0.25).isActive = true
        ratingStar.widthAnchor.constraint(equalTo: ratingBackground.widthAnchor, multiplier: 0.25).isActive = true

        ratingLabel.centerYAnchor.constraint(equalTo: ratingStar.centerYAnchor).isActive = true
        ratingLabel.rightAnchor.constraint(equalTo: ratingBackground.centerXAnchor, constant: -2).isActive = true

        regionLabel.centerXAnchor.constraint(equalTo: regionView.centerXAnchor).isActive = true
        regionLabel.centerYAnchor.constraint(equalTo: regionView.centerYAnchor).isActive = true

        regionView.rightAnchor.constraint(equalTo: micImageView.leftAnchor, constant: -(frame.width * 0.01)).isActive = true
        regionView.centerYAnchor.constraint(equalTo: micImageView.centerYAnchor).isActive = true
        regionView.heightAnchor.constraint(equalTo: micImageView.heightAnchor).isActive = true
        regionView.widthAnchor.constraint(equalTo: regionLabel.widthAnchor, multiplier: 1.4).isActive = true

        platformLabel.centerXAnchor.constraint(equalTo: platformView.centerXAnchor).isActive = true
        platformLabel.centerYAnchor.constraint(equalTo: platformView.centerYAnchor).isActive = true

        platformView.rightAnchor.constraint(equalTo: regionView.leftAnchor, constant: -(frame.width * 0.01)).isActive = true
        platformView.centerYAnchor.constraint(equalTo: regionView.centerYAnchor).isActive = true
        platformView.heightAnchor.constraint(equalTo: regionView.heightAnchor).isActive = true
        platformView.widthAnchor.constraint(equalTo: platformLabel.widthAnchor, multiplier: 1.5).isActive = true

        connectButton.rightAnchor.constraint(equalTo: micImageView.rightAnchor).isActive = true
        connectButton.bottomAnchor.constraint(equalTo: cellView.bottomAnchor, constant: -(frame.height * 0.1)).isActive = true
        connectButton.topAnchor.constraint(equalTo: separatorView.bottomAnchor, constant: frame.height * 0.05).isActive = true
        connectButton.widthAnchor.constraint(equalTo: cellView.widthAnchor, multiplier: 0.4).isActive = true
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

Am I doing something wrong that is taking up the memory or am I trying to do too much in a collectionviewcell?If so, what would I use as an alternative?

Usman Maqbool
  • 3,351
  • 10
  • 31
  • 48
  • 1
    If I had to guess, I'd say that the problems lies within the AsyncImageView class. I assume you are loading images into those views that may vary in size. That library has been deprecated since iOS 9, so it might lead to some unexpected behavior. You might want to try another image downloader library like [SDWebImage](https://github.com/SDWebImage/SDWebImage). – Mark Barrasso Apr 17 '19 at 04:26
  • One more thing I do like to add to Mark's comment is that, we usually don't download or provide data like images and other stuff through the cell's class directly. And also make sure you are using reusable cell in your "collectionView(_:cellForItemAt:)" func. – Akash Bhardwaj Apr 17 '19 at 05:09
  • Can you share the code where you are dequeuing the Cells , – Pavan Apr 17 '19 at 06:26

1 Answers1

0

The layer's masksToBounds and cornerRadius will trigger Offscreen rendering

LINKS: What triggers offscreen rendering, blending and layoutSubviews in iOS?

杨西川
  • 51
  • 3