Sean
Sean

Reputation: 341

How to initialize a cell with text using init

I'm getting stuck with trying to initialize a UICollectionViewCell subclass with some text :( I'm of course quite new to initializers, and my usual lame workaround (for passing data in general, not for cells) is to call a setup function to pass info afterwards. Any wise words? Many thanks in advance.

class MainCell: UICollectionViewCell {
    let titleLbl: UILabel = {
        let lbl = UILabel() // other stuff was in here
        lbl.text = "Placeholder text"
        return lbl
    }()    
    override init(frame: CGRect) {
        super.init(frame: frame)
        setupViews()
    }
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        setupViews()
    }
    func setupViews() {
        // adding to subviews, constraints, etc. Placeholder text works.
    }
}


class SubCell: MainCell {
    convenience init(title: String) {
        self.init()
        titleLbl.text = title
    }
}


SubCell(title: "Test") // doesn't return a cell with "Test" in the label

Solved: Wanted to share my solution in case it could ever help someone out. As @rmaddy pointed out, I was dequeuing cells that weren't getting initialized with my string.

I’ve seen typically these are based on arrays and passing data that way. But I have 4 cells with different elements, and I would like to avoid indexPath logic if possible.

My solution (I’m sure I’m not the only one, but I couldn’t find this anywhere) was to make custom classes for every cell, like how view controllers work. Now I have an array that contains the cells, and if I need to add a new one, I create the cell class and add it to the list without messing with any cellId's or indexPath stuff. Sorry to go on, I’m pretty new and am really excited. Here's my code if anyone wants to roast it:

class ViewController: UICollectionViewController, UICollectionViewDelegateFlowLayout {


    let cells = [CellOne(), CellTwo(), CellThree(), CellFour()]
    // subclasses of UICollectionViewCell, defined elsewhere


    override init(collectionViewLayout layout: UICollectionViewLayout) {
        super.init(collectionViewLayout: layout)
    }


    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }


    override func viewDidLoad() {
        super.viewDidLoad()
        collectionView.backgroundColor = bgColor

        for cell in cells {
            collectionView.register(type(of: cell), forCellWithReuseIdentifier: String(describing: type(of: cell)))
        }
    }


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


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


    override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cellType = type(of: cells[indexPath.item])
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: String(describing: cellType), for: indexPath)
        return cell
    }
}

Upvotes: 0

Views: 1412

Answers (1)

rmaddy
rmaddy

Reputation: 318884

You don't want to pass the string in the initializer. Cells get reused and you need to update existing cells. Create the cell normally and then update the tltleLbl property separately in cellForRowAt.

Something like:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "whatever" for: indexPath)
    cell.titleLbl.text = // whatever value is appropriate for this row

    return cell
}

Upvotes: 2

Related Questions