Anton
Anton

Reputation: 947

UITableView performance problem with HeaderCell

I have a performance issue when HeaderCell becomes visible, it takes up to 40% of CPU on iPhone X and I see lags. This UITableView displays static data (TV guide). I see lags every time when I scroll up and down, "tableView.dequeueReusableCell()" doesn't help. If I use my ExpandableHeaderView() to create HeaderCell for supporting tapping and expanding section, I have the same issue. If expand section and scrolls inside elements, I do not see lags. Performance problem occurs only when HeaderCell appears on the screen. When user opens View Controller, he sees 3 programs for each channel (current and next two), if he taps on section name, he sees all programs for section (channel). HeaderCell contains only Label. I display the same data in the same way on my Android app and it works without any problems on simple Android device.

func numberOfSections(in tableView: UITableView) -> Int {
        return Channels.count
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return Channels[section].Programs.count
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: reuseIdentifier)! as! TVGuideTableViewCell
        let dateFormatter = DateFormatter()
        dateFormatter.dateFormat = "HH:mm"
        let text = Channels[indexPath.section].Programs[indexPath.row].Name
        let dateString = dateFormatter.string(from:Channels[indexPath.section].Programs[indexPath.row].StartDate!)
        cell.label.text = text
        cell.timeLabel.text = dateString

        if (Channels[indexPath.section].Programs[indexPath.row].EndDate! < currentDate) {
            cell.label.textColor = UIColor.gray
        } else {
            cell.label.textColor = UIColor.white
        }

        if (Channels[indexPath.section].Programs[indexPath.row].StartDate! < currentDate) {
            cell.bell.isHidden = true
        } else {
            cell.bell.isHidden = false
        }

        if (Channels[indexPath.section].Programs[indexPath.row].EndDate! < currentDate) {
            Channels[indexPath.section].Programs[indexPath.row].expandedRow = false
        } else {
            if Channels[indexPath.section].expandedCount < 3 {
                Channels[indexPath.section].expandedCount += 1
                Channels[indexPath.section].Programs[indexPath.row].expandedRow = true
            }
        }

        return cell
    }

    func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
        let headerCell = tableView.dequeueReusableCell(withIdentifier: reuseIdentifierHeader) as! CustomHeaderTableViewCell
        headerCell.headerLabel.text = Channels[section].Name
        return headerCell
//        let header = ExpandableHeaderView()
//        header.customInit(title: Channels[section].Name, section: section, delegate: self as ExpandableHeaderViewDelegate)
//        return header
    }

    func toggleSection(header: ExpandableHeaderView, section: Int) {
        Channels[section].expanded = !Channels[section].expanded
        Channels[section].expandedCount = 0
        tableView.beginUpdates()
        for i in 0 ..< Channels[section].Programs.count {
            tableView.reloadRows(at: [IndexPath(row: i, section: section)], with: .automatic)
        }
        tableView.endUpdates()
    }

    func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
        return 38
    }

    func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
        return 2
    }

    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        if(Channels[indexPath.section].expanded) {
            return 38
        } else {

            if (Channels[indexPath.section].Programs[indexPath.row].EndDate! < currentDate) {
                return 0
            } else {
                if Channels[indexPath.section].Programs[indexPath.row].expandedRow {
                    return 38.0
                } else {
                    return 0.0
                }
            }

        }
    }

class CustomHeaderTableViewCell: UITableViewCell {


    @IBOutlet weak var headerLabel: UILabel!

    override func awakeFromNib() {
        super.awakeFromNib()
        // Initialization code
    }

    override func setSelected(_ selected: Bool, animated: Bool) {
        super.setSelected(selected, animated: animated)

        // Configure the view for the selected state
    }

}

Upvotes: 0

Views: 40

Answers (1)

Sohel L.
Sohel L.

Reputation: 9540

From your code, what I can see that the problem is not HeaderCell, the problem is DateFormatter object. Because everytime you scroll and cell appears a new object is created and just imagine that if there are 10 - 15 cells at a time then 10 - 15 reused / created and as you scroll or reloadData it again create a new object.

So, my advise is to create the DateFormatter object outside cellforRow and then just use it to get to get a dateString by calling it.

This is just one assumption, try this and project still appears do let me know!

Upvotes: 1

Related Questions