注册我不使用的单元格是否会对性能造成很大影响?

kev*_*vin 4 ios swift swift3

我有UITableViewCells单独的 xib,因为我在我的应用程序中多次重复使用它们。我现在有一个要在 every 中注册的单元格的小列表UITableViewController,如下所示:

// viewdidload
    tableView.register(UINib(nibName: "KeyTextCell", bundle: nil), forCellReuseIdentifier: "KeyTextCell")
    tableView.register(UINib(nibName: "KeyValueCell", bundle: nil), forCellReuseIdentifier: "KeyValueCell")
    tableView.register(UINib(nibName: "KeyEditFieldCell", bundle: nil), forCellReuseIdentifier: "KeyEditFieldCell")
    tableView.register(UINib(nibName: "KeyTwoEditFieldCell", bundle: nil), forCellReuseIdentifier: "KeyTwoEditFieldCell")
    tableView.register(UINib(nibName: "KeyThreeEditFieldCell", bundle: nil), forCellReuseIdentifier: "KeyThreeEditFieldCell")
    tableView.register(UINib(nibName: "KeySwitchCell", bundle: nil), forCellReuseIdentifier: "KeySwitchCell")
    tableView.register(UINib(nibName: "TextCell", bundle: nil), forCellReuseIdentifier: "TextCell")

//cellForRow...
    let cell = tableView.dequeueReusableCell(withIdentifier: "KeyValueCell") as! KeyValueCell
Run Code Online (Sandbox Code Playgroud)

我必须先将任何新单元添加到此列表中,然后才能在该控制器中使用该单元,这很烦人并且很容易忘记。除此之外,在我的 viewDidLoad 中注册一个单元格列表是很丑陋的,而且在某些地方它会变得很长。
所以我想让这变得更好。我正在考虑在UITableViewController扩展中创建一个小函数来注册我拥有的所有单元格。这意味着只需维护一个列表,而且还要注册该特定控制器中可能不需要的单元格。注册不必要的单元是否会对性能造成(大)影响?还有其他缺点吗?最佳实践是什么?

dea*_*rne 6

有两种方式会让你付出代价 - 在 vi​​ewDidLoad 时注册所有笔尖,以及在tableView(_:cellForRowAt:)创建/回收单元格时。

1.在viewDidLoad中

让我们详细看看该行:

tableView.register(UINib(nibName: "KeyTextCell", bundle: nil), forCellReuseIdentifier: "KeyTextCell")
Run Code Online (Sandbox Code Playgroud)

这里发生了两件事:

  1. 创建一个UINib对象

创建一个UINib非常快 - 它甚至不会检查笔尖是否存在,直到您询问它的内容。您可以使用以下代码进行测试:

let nib = UINib(nibName: "Doesn't exist", bundle: nil)
print(nib) // Prints out something like `<UINib: 0x60000001fba0>`

// This line will load the nib and unpack it into the view.
// It's obviously going to fail :)
let view = nib.instantiate(withOwner: nil, options: [:])
Run Code Online (Sandbox Code Playgroud)

另外,阅读 UINib 的文档会告诉您,它会从磁盘加载一次内容并将其缓存,因此无论您从 nib 创建单元格多少次,您都只会在第一次需要时访问。

  1. 将其注册到表视图中

这几乎相当于将一个项目插入到字典中 - 考虑到你的字典有多小(大约 7 个项目?),这会很快。所以我不会担心注册时间(不过,您应该对此进行测试,请参见下文)。

2. 在tableView(_:cellFrorRowAt:)

在 中创建/出队一个单元怎么样tableView(_:cellFrorRowAt:)?我们可以忽略使现有单元出列 - 这与从笔尖加载单元无关 - 该单元已经加载并在内存中 - 所以我们关心的是当您请求一个单元但没有准备好的单元时被回收。考虑到平均表视图高度,对于第一个充满行的屏幕,这种情况会发生 10-15 次。之后,他们将开始回收。

如果我们假设 tableViews 将它们的 nib 存储在类似字典的东西中,这将非常快 - 字典访问是 O(1),所以注册多少个单元格并不重要。然而,如果它存储为数组或集合之类的东西,那么当您添加更多项目时访问会变慢,但您只添加 7 个项目,所以它仍然相当快:)

3. 测试这一切

这主要是猜测 - 找出影响的最佳方法是在真实设备上进行测试(选择您的客户可能使用的最差设备!)

测试此功能的肮脏方法是仅注册 10000 个 nib(在 viewDidLoad 中编写循环)并查看应用程序的执行情况。如果 10,000 没问题,那么 7 也可以;)

测试此功能的最佳方法是使用 Instruments 对其进行分析 - 按 CMD-i(而不是 CMD+r)在 Instruments 中运行代码,然后 Instruments 将打开。选择“时间分析器”并按左上角的红色记录按钮 - 这将运行您的应用程序,但会记录所有发生的方法调用等。让应用程序启动并稳定下来(当您的应用程序启动时,活动图会进入心理状态,然后当您的应用程序只是坐在那里等待您与其交互时,活动图应该会下降到什么都没有)。然后,您可以导航到注册了所有这些笔尖的视图控制器,您可以看到打开视图控制器需要多少活动,以及滚动需要多少活动等。尝试仅注册一个笔尖,然后尝试使用注册10000就可以看到差别。

您还可以在屏幕下半部分看到按时间细分的函数调用 - 如果您单击此处,您可以找到一些有关哪些调用花费很长时间的有用信息。

希望这对您有所帮助 - Instruments 可以做很多更有用的事情 - 值得点击一下并查看可用的内容。这里有文档:https://developer.apple.com/library/content/documentation/DeveloperTools/Conceptual/InstrumentsUserGuide/index.html

另一件要考虑的事情是内存 - 如果您在所有表视图中注册所有这些笔尖,那么您可能会使用不需要的内存,但我会再次在仪器中对此进行分析,看看命中是什么。我的直觉是,你不必担心,UINib 只加载它需要的内容,而且我敢打赌,当内存不足警告到达时,UINib 会清除它的缓存:)

tl;dr 如果您的应用程序滚动顺畅,我不会担心 7 个笔尖。