简体   繁体   中英

Dequeuing reusable cell in Swift 3 is incredibly slow

Dequeuing a cell is taking 0.5-1.0 seconds which means that my UITableView takes more than 2-3 full seconds to load even though it only has 4 rows.

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    var cellid = "NumberCell"
    var isnumber = true
    if indexPath.row == 0 {
        cellid = "TextCell"
        isnumber = false
    }

    NSLog("before dequeue \(indexPath)")
    let cell = tableView.dequeueReusableCell(withIdentifier: cellid, for: indexPath) as! TextfieldTableViewCell
    NSLog("dequeued")

    // ...

    return cell
}

The NSLog() statements directly before and after show that the dequeue takes from 07.47 to 08.38 .

2017-07-25 22:07:07.471898-0700 myapp[10209:4507471] before dequeue [0, 0]

2017-07-25 22:07:07.679715-0700 myapp[10209:4507471] [MC] System group container for systemgroup.com.apple.configurationprofiles path is /private/var/containers/Shared/SystemGroup/systemgroup.com.apple.configurationprofiles

2017-07-25 22:07:07.683843-0700 myapp[10209:4507471] [MC] Reading from public effective user settings.

2017-07-25 22:07:08.386960-0700 myapp[10209:4507471] dequeued

The cell is very simple. It just has a UILabel and a UITextField and the UITextField has an Editing Changed action. That's it.

在此处输入图片说明

What the heck could possibly be causing it to take SO long to dequeue a cell? Is it those other two system NSLog()s about the System group container?

It makes my app almost unusable because when I try to segue to this view controller the app appears to lock up for 2-4 seconds while it's setting up the 4 rows.

I've made hundreds of UITableViewControllers in Objective-C and I've never had this problem. Is there something weird about Swift 3 that I'm missing?

2017-07-25 22:07:07.679715-0700 myapp[10209:4507471] [MC] System group container for systemgroup.com.apple.configurationprofiles path is /private/var/containers/Shared/SystemGroup/systemgroup.com.apple.configurationprofiles

2017-07-25 22:07:07.683843-0700 myapp[10209:4507471] [MC] Reading from public effective user settings.

⚠️ This is a log from OS Level . which delay in dequeuing your UITableCell

You can disable unwanted log in xcode . like below

1- From Xcode menu open: Product > Scheme > Edit Scheme

2- On your Environment Variables set OS_ACTIVITY_MODE in the value set disable

在此处输入图片说明

You will face this problem only when you are debugging the app . this will run fine on real device .

I finally figured out the problem and it was entirely my fault. I was accidentally requesting first responder on every field.

For convenience, I had overridden setSelected(_:animated:) so that if I touched the row that row's textfield would become first responder (just in case I tried to tap on a field and missed). The problem was that I forgot to put an if statement around the becomeFirstResponder() call.

Bad code:

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

    self.textfield.becomeFirstResponder()
}

After dequeuing a cell it would set it to selected=false by default which would cause it to try to become first responder. It was a dumb mistake on my part.

Here's what I intended to do:

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

    if selected {
        self.textfield.becomeFirstResponder()
    }
}

I don't think there is any problem with this piece of code. And I don't think the dequeue code really lasts for so long unless you're missing some important issues in your code. If your table view is as simple as you said, that wouldn't take so long. But to debug that, you must consider these points:

  • NSLog is not a trustworthy timer for checking dequeue 's duration. You should use the code below to calculate the time accurately:

    let start = CACurrentMediaTime()
    let cell = tableView.dequeueReusableCell(withIdentifier: cellid, for: indexPath) as! TextfieldTableViewCell
    let finish = CACurrentMediaTime()
    print("dequeue time:(finish - start)")

  • If the dequeue time is acceptable, your performance issue is not caused by it.

  • If the dequeue time is still not acceptable. One reason makes sense is that you have only four rows of your tableview and none of them are higher than the tableview, so tableview is not going to use the cell from the buffer but going to create a cell from the bottom up. And this operation is far more time-consuming than using the cell from the buffer. But this process is inevitable because every app using tableview will encounter it. Therefore, you should consider if your simulator(Assumed you're using a simulator) is too slow to run your app. Because the speed between simulator and real iPhone is quite different.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM