In my custom UITableViewCell
when the property is set, if there is no label it will create a label and set the text etc. If the label already exists, it shouldn't do anything. The strange thing is, when I tap the cell for the first time it creates the label as it should be. But when I tap the cell again, the label disappears. I've recreated this in a clean project and same thing is happening. What's the cause of this odd behavior?
CustomTableViewCell:
class TableViewCell: UITableViewCell {
var numberLabel: UILabel!
var views = [String: UILabel]()
var number: Int = 5 {
didSet {
println("AMOUNT: Accessed")
if numberLabel == nil {
println("AMOUNT: Amount is nil")
// Create amount label
numberLabel = UILabel()
if number > 0 { numberLabel.text = String(number) }
numberLabel.setTranslatesAutoresizingMaskIntoConstraints(false)
contentView.addSubview(numberLabel)
views["amount"] = numberLabel
// Amount label constraints
contentView.addConstraint(NSLayoutConstraint(item: numberLabel, attribute: .CenterY, relatedBy: .Equal, toItem: contentView, attribute: .CenterY, multiplier: 1, constant: 0))
contentView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:[amount(40)]-8-|", options: nil, metrics: nil, views: views))
} else {
println("AMOUNT: Nothing should be changing or happening \n")
}
}
}
required init(coder aDecoder: NSCoder) {
fatalError("NSCoding not supported")
}
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
}
}
ViewController:
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
@IBOutlet weak var tableView: UITableView!
var items = [Int]()
var amount = 0
override func viewDidLoad() {
super.viewDidLoad()
tableView.registerClass(TableViewCell.self, forCellReuseIdentifier: "cell")
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return 1 }
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as TableViewCell
cell.number = amount
return cell
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
amount++
tableView.reloadRowsAtIndexPaths([indexPath], withRowAnimation: .Fade)
}
}
EDIT: In response to the comment, my console displays:
NUMBER: Accessed
NUMBER: Number is nil
NUMBER: Accessed
NUMBER: Number is nil << label shows "1"
NUMBER: Accessed
NUMBER: Nothing should be changing or happening << label disappears.
NUMBER: Accessed
NUMBER: Nothing should be changing or happening << label shows "1" again
NUMBER: Accessed
NUMBER: Nothing should be changing or happening << label disappears.
NUMBER: Accessed
NUMBER: Nothing should be changing or happening << label shows "1" again
NUMBER: Accessed
NUMBER: Nothing should be changing or happening << label disappears.
I also changed the background to a color and it just disappears. I suppose it has something to do with the oldValue
of didSet. The same is happening with willSet
when I change the values to newValue
. Nothing happens when I use the "old values" though.
I believe this is down to the repeated reuse of the same two cells:
Your table only has one row, but you end up creating two cells from scratch which is clear from the initial output. It probably creates two because you reload while using the first cell, forcing a second to be created.
The first cell (A) will have the number 0 and a blank label. The second cell (B) will have the number 1 and a label with 1 in it.
When you do the next select, the table reuses cell A which has blank text. Regardless of the number this will always be blank as you never reset the number for a cell which has a label already.
When you do the next select, the table reuses cell B which has text with a 1.
This pattern then repeats because you are always using one cell while calling reload which reuses the other. Hence A,B,A,B.....
To fix the problem, you need to set the label content every time you set the number.