0

I have UITableView with 2 expanded Sections. So, when I click on section's header, rows will be hidden:

override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {

    print("Section: \(indexPath.section), Row \(indexPath.row), \(sections[indexPath.section].expanded)")

    if sections[indexPath.section].expanded {
        return 88
    } else {
        return 0
    }
}

I am adding an UIlabel to a cell in UITableView as below:

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

    let cell = tableView.dequeueReusableCell(withIdentifier: cellId, for: indexPath)

    let label = UILabel()
    cell.contentView.addSubview(label)
    label.translatesAutoresizingMaskIntoConstraints = false

    label.leftAnchor.constraint(equalTo: cell.leftAnchor).isActive = true
    label.topAnchor.constraint(equalTo: cell.topAnchor).isActive = true
    label.widthAnchor.constraint(equalTo: cell.widthAnchor).isActive = true
    label.heightAnchor.constraint(equalToConstant: 30).isActive = true

    label.text = "row = \(indexPath.row)"

    return cell
}

The above is working but cells are not properly showing the screen as sometime, the content of row1 is printed in another row.

If I add the below code, and when I click on a header of any section, the rows will be properly showing on the tableView, but just one time, I mean if I click one more time on the header, an error occurs inside CellForRowAt function (Thread 1: EXC_BAD_ACCESS (code=EXC_I386_GPFLT)):

cell.contentView.layer.sublayers?.forEach { $0.removeFromSuperlayer() }

Any advise?

EDIT: just to explain how the sections are expanded, i will add the following:

protocol ExpandableHeaderViewDelegate {
    func toggleSection(header: ExpandableHeaderView, section: Int)
}

class ExpandableHeaderView: UITableViewHeaderFooterView {

    var delegate: ExpandableHeaderViewDelegate?
    var section: Int!

    override init(reuseIdentifier: String?) {
        super.init(reuseIdentifier: reuseIdentifier)

        self.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(selectHeaderAction)))
    }

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

    @objc func selectHeaderAction(gestureRecognizer: UITapGestureRecognizer) {
        let cell = gestureRecognizer.view as! ExpandableHeaderView
        delegate?.toggleSection(header: self, section: cell.section)
    }

    func toggleSection(header: ExpandableHeaderView, section: Int) {
        tableView.beginUpdates()
        tableView.endUpdates()
    }

}
maxwell
  • 3,788
  • 6
  • 26
  • 40
Xin Lok
  • 496
  • 1
  • 6
  • 21

4 Answers4

1

My question was solved by [Knight0fDragon].

    extension UIView
{
    func clearSubviews()
    {
        for subview in self.subviews as! [UIView] {
            subview.removeFromSuperview();
        }
    }
}

and then

        cell.contentView.clearSubviews()

Thanks for all kind people for their support.

Xin Lok
  • 496
  • 1
  • 6
  • 21
0

If the problem is just for mismatch of cell data then try using

override func prepareForReuse() {
    super.prepareForReuse()
    self.label.text = ""
}

Declare the UILabel in the cell's class with null value instead of declaring it in cellForRowAt

Abhishek Master
  • 192
  • 2
  • 19
0

Try this inside cellForRowAt:

if tableView.rectForRow(at: indexPath).height == 0.0 {
            return UITableViewCell()
}

It should be above all other code.

Farhan Arshad
  • 375
  • 3
  • 9
0

Try (call it before adding new label)

cell.contentView.subviews.removeAll() 

instead of

cell.contentView.layer.sublayers?.forEach { $0.removeFromSuperlayer() } 
Farhan Arshad
  • 375
  • 3
  • 9
  • It didn't works, it gave error "Cannot use mutating member on immutable value: 'subviews' is a get-only property" – Xin Lok Feb 07 '18 at 09:13