Swift UITableViewCell shows data hidden by default
I have a seemingly random problem where some of the cells in mine are UITableView
showing data that should be hidden by default.
Explain hidden data.
This is a portfolio of stocks where you can click on a cell to expand it (and see this data). When it closes, the data is hidden again.
Here is a screenshot of the problem I ran into causing random cells to display this data by default.
On the screenshot above it there are cells "RUS.TO" and "CUB", which display hidden data.
This is where views and labels are created to be hidden:
// #Advanced data
stockNameView.setTranslatesAutoresizingMaskIntoConstraints(false)
stockNameView.hidden = true
self.addSubview(stockNameView)
purchasePriceView.setTranslatesAutoresizingMaskIntoConstraints(false)
purchasePriceView.hidden = true
self.addSubview(purchasePriceView)
lastPriceView.setTranslatesAutoresizingMaskIntoConstraints(false)
lastPriceView.hidden = true
self.addSubview(lastPriceView)
daysHeldView.setTranslatesAutoresizingMaskIntoConstraints(false)
daysHeldView.hidden = true
self.addSubview(daysHeldView)
The 8 labels that overlap are subspecies of the above representations.
As you can see, these 4 views are hidden by default. So I don't think the problem is with my cell class?
There is only one place in my code where I am setting the hidden value of these 4 UIViews to false.
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("com.Stocks.portfolioCell", forIndexPath: indexPath) as! portfolioCell
if indexPath.row % 2 == 0 {
cell.backgroundColor = UIColor.whiteColor()
} else {
cell.backgroundColor = UIColor.formulaWhiteColor()
}
if selectedCellIndexPath == indexPath {
cell.tickerLabel.textColor = UIColor.formulaBlueColor()
cell.heightSeperator.hidden = false
cell.stockNameView.hidden = false
cell.purchasePriceView.hidden = false
cell.lastPriceView.hidden = false
cell.daysHeldView.hidden = false
cell.endSeperator.hidden = false
tableHeight.constant = tableHeight.constant+250
self.scrollView.contentSize = CGSize(width:self.view.bounds.width, height: self.contentView.frame.height)
}
if lastCollapsing == true || currentCollapsing == true {
cell.tickerLabel.textColor = UIColor.formulaDarkGrayColor()
cell.heightSeperator.hidden = true
cell.stockNameView.hidden = true
cell.purchasePriceView.hidden = true
cell.lastPriceView.hidden = true
cell.daysHeldView.hidden = true
cell.endSeperator.hidden = true
lastCollapsing = false
currentCollapsing = false
tableHeight.constant = tableHeight.constant-250
self.scrollView.contentSize = CGSize(width:self.view.bounds.width, height: self.contentView.frame.height)
}
if stocks.count > 0 {
let formulaStock = stocks[indexPath.row]
ticker = formulaStock.valueForKey("ticker") as! String!
let fontAwesomeBlueAttribute = [NSForegroundColorAttributeName: UIColor.formulaBlueColor(), NSFontAttributeName: UIFont(name: "FontAwesome", size: 12)!]
let fontAwesomeGreenAttribute = [NSForegroundColorAttributeName: UIColor.formulaGreenColor(), NSFontAttributeName: UIFont(name: "FontAwesome", size: 12)!]
let latoBoldDarkGrayAttribute = [NSForegroundColorAttributeName: UIColor.formulaDarkGrayColor(), NSFontAttributeName: UIFont(name: "Lato-Bold", size: 12)!]
if ticker != "CASH" {
let tickerString = " \(ticker)" as NSString
var tickerAttributedString = NSMutableAttributedString(string: tickerString as String)
tickerAttributedString.addAttributes(fontAwesomeBlueAttribute, range: tickerString.rangeOfString(""))
tickerAttributedString.addAttributes(latoBoldDarkGrayAttribute, range: tickerString.rangeOfString(" \(ticker)"))
cell.tickerLabel.attributedText = tickerAttributedString
} else {
let tickerString = " \(ticker)" as NSString
var tickerAttributedString = NSMutableAttributedString(string: tickerString as String)
tickerAttributedString.addAttributes(fontAwesomeGreenAttribute, range: tickerString.rangeOfString(""))
tickerAttributedString.addAttributes(latoBoldDarkGrayAttribute, range: tickerString.rangeOfString(" \(ticker)"))
cell.tickerLabel.attributedText = tickerAttributedString
}
weight = formulaStock.valueForKey("weight") as! Float
cell.weightLabel.text = "\(weight.roundTo(2))%"
cell.filledWeightWidth.constant = CGFloat(weight/2)
lastPrice = formulaStock.valueForKey("lastPrice") as! Float
purchasePrice = formulaStock.valueForKey("purchasePrice") as! Float
percentDifference = ((lastPrice/purchasePrice)*100.00)-100
if ticker == "CASH" {
cell.changeLabel.text = ""
} else if percentDifference > 0 {
cell.changeLabel.text = ("+\(percentDifference.roundTo(2))%")
cell.changeLabel.textColor = UIColor.formulaGreenColor()
} else if percentDifference < 0 && percentDifference > -100 {
cell.changeLabel.text = ("\(percentDifference.roundTo(2))%")
cell.changeLabel.textColor = UIColor.formulaRedColor()
} else if percentDifference == 0 {
cell.changeLabel.text = ("\(percentDifference.roundTo(2))%")
cell.changeLabel.textColor = UIColor.formulaGreenColor()
} else {
cell.changeLabel.text = "N/A"
cell.changeLabel.textColor = UIColor.formulaDarkGrayColor()
}
cell.stockNameLabel.text = formulaStock.valueForKey("name") as! String!
cell.purchasePriceLabel.text = "$\(purchasePrice)"
cell.lastPriceLabel.text = "$\(lastPrice)"
daysHeld = formulaStock.valueForKey("daysHeld") as! Int
cell.daysHeldLabel.text = "\(daysHeld)"
}
cell.selectionStyle = UITableViewCellSelectionStyle.None
return cell
}
But the section of code that sets hidden cell values to false. It requires mine to selectedCellIndexPath
be equal to the current index that it is passing through cellForRowAtIndexPath
.
Here's where I am setting selectedCellIndexPath
:
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let cell = tableView.dequeueReusableCellWithIdentifier("com.Stocks.portfolioCell", forIndexPath: indexPath) as! portfolioCell
if let selectedCellIndexPath = selectedCellIndexPath {
if selectedCellIndexPath == indexPath {
self.selectedCellIndexPath = nil
currentCollapsing = true
tableView.reloadRowsAtIndexPaths([indexPath], withRowAnimation: .None)
} else {
lastCollapsing = true
self.selectedCellIndexPath = indexPath
tableView.reloadRowsAtIndexPaths([lastIndexPath], withRowAnimation: .None)
tableView.reloadRowsAtIndexPaths([indexPath], withRowAnimation: .None)
self.lastIndexPath = indexPath
}
} else {
selectedCellIndexPath = indexPath
self.lastIndexPath = indexPath
tableView.reloadRowsAtIndexPaths([indexPath], withRowAnimation: UITableViewRowAnimation.None)
}
tableView.beginUpdates()
tableView.endUpdates()
}
Which should ever be when I click on a cell.
Every time I supply a UITableView with a new dataset, I also have to run the following line of code:
(menuTabBarController.viewControllers as! [Portfolio_ViewController])[1].selectedCellIndexPath = nil
Specifies selectedCellIndexPath
nil to avoid potential problems.
So why do some random cells display information that should be hidden by default?
When I tested this error, I was not using any cells. This way the selectedCellIndex should never have a value at this point.
source to share
When you reuse a cell, the old values are still stored on it, so every time you use dequeueReusableCellWithIdentifier
you need to reset the defaults or the last values still cached in it.
The table covers the implementation of the data source tableView: cellForRowAtIndexPath: Always reset all content when reusing a cell.
source to share
As @chedabob mentioned in his comment. UITableViewCell will call prepareForReuse()
before reusing the cell. Reset your views and meaning in it. So, inside the tableviewcell class, override the methodprepareForReuse()
//Inside your UITableViewCell
override func prepareForReuse() {
//Reset cell values here
}
source to share