Search code examples
iosswiftuitableviewdatasource

Why UITableVIew Display Data Incorrectly After Scrolling


My code is very simple. I have a fixed list of string to be displayed on UITableView, with custom UITableViewCell, which only has a UILabel on it.

My problem is that altho the data was displayed correctly initially, it displayed incorrectly after scrolling.

Here are more details. DataSource is a list [(String, something_else)]

The content of the list is

[("aaaaaa", something),
("bbbbbb", something),
("cccccc", something),
   ...
("rrrrrr", something)]

The screen is big enough to display "aaaa" to "mmmm". When I scroll down, the next visible line should be "nnnn", but it was "rrrr", after "rrrr" was "aaaa", "bbbb", "cccc", then I scroll up, it gave me "eeee", "cccc", "rrrr". It was slightly different every time I restarted the simulator.

As you can see in the code below, I added print(cell.note) every time cell was dequeued and cell.note was set, but the printed messages in console indicate cells were set to the correct note. Yes, it looked correct. After "mmm", it was n,o,p,q,r, then I scroll up, it was f,e,d,c,b,a, it looked correct.

I don't understand why and I don't know how to solve it. Googling didn't give anything so I wanna try finding help here. Thank you for reading this.

Below are my code. Very simple implementation of dataSource and delegate

extension ViewController: UITableViewDelegate, UITableViewDataSource {
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        data.count;
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableview?.dequeueReusableCell(withIdentifier: "NoteNodeCell") as! NoteNodeCell
        cell.note = data[indexPath.row].0        
        return cell
    }
    
    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return 64
    }
}

NoteNodeCell is a custom UITableViewCell. I basically only added a UILabel in it.

class NoteNodeCell: UITableViewCell {
    var note: String {
        get { cellView.note }
        set { cellView.note = newValue }}
    
    var cellView:CellView = CellView()
    
    override func awakeFromNib() {
        super.awakeFromNib()
        
        if cellView.superview != contentView {
            contentView.addSubview(cellView)
        }
        
        cellView.translatesAutoresizingMaskIntoConstraints = false
        cellView.topAnchor.constraint(equalTo: contentView.topAnchor).isActive = true
        cellView.leftAnchor.constraint(equalTo: contentView.leftAnchor).isActive = true
        cellView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor).isActive = true
        cellView.rightAnchor.constraint(equalTo: contentView.rightAnchor).isActive = true
        
    }
    
    override func prepareForReuse() {
        super.prepareForReuse()
        note = ""
    }
}


class CellView: UIView {
    var note = "" { didSet { print(note) }}
    
    override func draw(_ rect: CGRect) {
        super.draw(rect)
        UIColor.white.setFill()
        UIRectFill(rect)
        let label = UILabel(frame: bounds)
        label.text = "  " + note
        label.font = UIFont(name: "Courier", size: 18)
        label.textColor = .white
        label.backgroundColor = .gray
        label.layer.cornerRadius = 5
        label.layer.masksToBounds = true
        UIColor.clear.setFill()
        addSubview(label)

    }
}

Thank you again for reading this.


Solution

  • Try this for your CellView class

    class CellView: UIView {
    let label = UILabel()
    var note = "" { 
        didSet { 
            print(note) 
            self.label.text = "  " + note // this
        }
    }
    
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        setupSubviews()
    }
    
    private func setupSubviews() {
        label.text = "  " + note
        label.font = UIFont(name: "Courier", size: 18)
        label.textColor = .white
        label.backgroundColor = .gray
        label.layer.cornerRadius = 5
        label.layer.masksToBounds = true
        addSubview(label)
    }
    

    }

    and your UITableViewCell would need this

    let cellView = CellView(frame: .zero)
    

    Let me know if this doesn't work