【问题标题】:Dequeuing reusable cell in Swift 3 is incredibly slow在 Swift 3 中出列可重用单元非常慢
【发布时间】:2018-01-01 06:12:11
【问题描述】:

使单元格出列需要 0.5-1.0 秒,这意味着我的 UITableView 需要超过 2-3 秒的时间来加载,即使它只有 4 行。

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
}

直接在前后的 NSLog() 语句表明出队从 07.4708.38

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

2017-07-25 22:07:07.679715-0700 myapp[10209:4507471] [MC] systemgroup.com.apple.configurationprofiles 路径的系统组容器是 /private/var/containers/Shared/SystemGroup/systemgroup。 com.apple.configurationprofiles

2017-07-25 22:07:07.683843-0700 myapp[10209:4507471] [MC] 从公共有效用户设置中读取。

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

单元格非常简单。它只有一个 UILabel 和一个 UITextField 并且 UITextField 有一个 Editing Changed 操作。就是这样。

到底是什么原因导致单元格出列需要这么长时间?是关于 System group 容器的其他两个系统 NSLog() 吗?

这使我的应用程序几乎无法使用,因为当我尝试使用此视图控制器时,应用程序似乎在设置 4 行时锁定了 2-4 秒。

我已经在 Objective-C 中制作了数百个 UITableViewController,但我从来没有遇到过这个问题。我错过了关于 Swift 3 的一些奇怪的东西吗?

【问题讨论】:

  • 你在用Nested ViewControllers吗?
  • 你用仪器中的时间分析器检查过代码吗?
  • 转到 Xcode -> 产品 -> 方案 -> 编辑方案 在环境变量中,添加 OS_ACTIVITY_MODE 作为名称并禁用作为值 试试这个,让我知道
  • 这似乎并不明显和必要。但是在 DispatchQueue.main.async 中编写你的代码,让我知道它是否能提高性能。将所有 dequeueReusable 代码放入其中。请让我知道它是否有效。

标签: ios swift uitableview swift3


【解决方案1】:

2017-07-25 22:07:07.679715-0700 myapp[10209:4507471] [MC] 系统组 systemgroup.com.apple.configurationprofiles 路径的容器是 /private/var/containers/Shared/SystemGroup/systemgroup.com.apple.configurationprofiles

2017-07-25 22:07:07.683843-0700 myapp[10209:4507471] [MC] 阅读自 公开有效的用户设置。

⚠️ 这是来自OS Level 的日志。延迟出队你的UITableCell

您可以禁用不需要的登录 xcode 。如下所示

1- 从 Xcode 菜单打开:Product > Scheme > Edit Scheme

2- 在值集disable 中设置环境变量OS_ACTIVITY_MODE

只有在调试应用时才会遇到这个问题。 这将在真实设备上运行良好。

【讨论】:

  • 问题确实发生在设备上。它与 sim 或运行方案无关。这是一个代码缺陷,我终于找到了。
【解决方案2】:

我终于找出了问题所在,这完全是我的错。我不小心要求每个领域的第一响应者。

为方便起见,我覆盖了setSelected(_:animated:),这样如果我触摸该行,该行的文本字段将成为第一响应者(以防我试图点击一个字段并错过了)。问题是我忘记在 becomeFirstResponder() 调用周围加上 if 语句。

错误代码:

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

    self.textfield.becomeFirstResponder()
}

在将一个单元格出列后,默认情况下会将其设置为 selected=false,这将导致它尝试成为第一响应者。这是我的一个愚蠢的错误。

这是我打算做的:

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

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

【讨论】:

    【解决方案3】:

    我认为这段代码没有任何问题。而且我认为dequeue 代码不会持续这么长时间,除非您在代码中遗漏了一些重要问题。如果您的表格视图像您说的那样简单,那不会花这么长时间。但要调试它,您必须考虑以下几点:

    • NSLog 不是用于检查dequeue 持续时间的可靠计时器。您应该使用下面的代码来准确计算时间:

      让开始 = CACurrentMediaTime()
      让 cell = tableView.dequeueReusableCell(withIdentifier: cellid, for: indexPath) as!文本字段TableViewCell
      让完成 = CACurrentMediaTime()
      print("出队时间:(完成-开始)")

    • 如果dequeue 时间是可以接受的,那么您的性能问题不是由它引起的。

    • 如果dequeue 时间仍然不可接受。有一个原因是有道理的,你的 tableview 只有四行,而且没有一个比 tableview 高,所以 tableview 不会使用缓冲区中的单元格,而是要自下而上创建一个单元格。而且这个操作比使用缓冲区中的单元格要耗时得多。但是这个过程是不可避免的,因为每个使用 tableview 的应用都会遇到它。因此,您应该考虑您的模拟器(假设您使用的是模拟器)是否太慢而无法运行您的应用程序。因为模拟器和真机的速度差别很大。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-04-22
      • 2012-06-13
      • 2019-07-22
      • 1970-01-01
      • 1970-01-01
      • 2017-03-01
      • 2018-10-12
      • 1970-01-01
      相关资源
      最近更新 更多