viewWillDisappear和viewDidDissapear之间的延迟

时间:2014-05-02 19:32:20

标签: ios objective-c performance optimization uiview

我在一段时间后看到我的应用程序性能下降,并且我试图弄清楚到底发生了什么。

我有一个复杂的视图控制器(VC1),它包含滚动视图,里面有几个表视图,一些带水平滚动的自定义单元格和自定义绘图等。

当我尝试调用presentViewController以将另一个视图控制器推送到VC​​1之上时,在几次(大约10次)刷新所有这些对象(重新加载表,重新定位子视图等)之后,我可以看到viewWillDisappear和{之间约2秒的延迟{1}}

我试图分析应用程序以查看是否存在内存泄漏但无法找到任何内存泄漏。当视图刷新并在不同模式之间切换时,内存使用量会增加,但随后在30米左右变得或多或少变得稳定。

在模拟器中工作正常,但在iPhone5上可见较慢。只有当我尝试切换viewDidDissapear视图控制器时,这种缓慢才会显现。

我跑了一个探查器并记录了这两秒钟的用武之地。以下是跟踪文件的链接:https://dl.dropboxusercontent.com/u/6402890/trace.trace.zip

我可以看到UIKit在布局上花费的大部分时间。

我可以做些什么来优化它?是否可以拍摄视图的快照并将其用于"离开视图"我们回来时动画和恢复视图层次结构?

更新:为探查器添加屏幕截图(点击查看完整分辨率):

screenshot

UPDATE2

在分析from的输出后,我可以看到以下内容:

  • 在最简单的情况下,输出中有~200行。而且表现还可以。
  • 当我切换到更复杂的场景层次结构时,视图增长到~500行,但仍然执行正常。
  • 多次刷新后,这个数字变为〜2000,这就是它变慢的地方。使用2000个视图分析输出我可以看到它们中的~1500个属于隐藏的单元格,甚至不再以此模式显示。当我刷新表格视图时,单元格类型也会发生变化,并且我正在使用不同的单元格,但为什么不再使用的单元格仍然在表格视图的子视图中?

有什么建议吗?

4 个答案:

答案 0 :(得分:3)

从您的筹码中,我怀疑您添加了大量您并不意味着添加的观看次数。由于它与重新加载有关,我会检查您的重新加载逻辑并确保它不会重新添加层次结构中的所有视图而不删除以前的视图。您可以编写快速调试例程使用-recursiveDescription递归遍历每个视图的-subviews并打印出来以查看层次结构中的内容。

您的问题可能出在图层层次结构而不是视图层次结构中,但您描述的症状会让我思考视图。


编辑:从您的更新中,您可能正在进行两件事之一。最有可能的是,如果这些实际上UITableViewCells不再存在,那么你就有了一个保留循环。或者,您的cellForRowAtIndexPath:可能不正确,可能只是在重新配置单元格时向现有单元格添加新视图。

在任何一种情况下,200个观看次数似乎都是最好的情况。"您可能会在应该进行自定义绘图的地方过度使用视图。如果性能还可以,那么......好吧,但我会在你支持最慢的设备上仔细测试。

答案 1 :(得分:2)

从Instruments Time Profiler输出中,您可以看到NSISEngine占用了大量的CPU。该类负责执行自动布局约束评估和布局计算。

所以看起来你正在使用自动布局,至少对于某些视图来说。

您是否有机会在运行时删除和重新添加约束?我已经看到了由此引起的确切问题(如果相关,可以解释更多)。

如果你没有删除约束,听起来你可能有一个相当复杂的视图层次结构,如果你在整个过程中使用自动布局,那么很可能你有很多约束。您可能知道,由于super-linear time complexity of solving constraints,自动布局的性能会在某个点之后迅速降低。检查调试器中po [[UIWindow keyWindow] recursiveDescription]的输出,以查看视图层次结构的外观。

我不确定您的视图控制器转换是什么样的,但您可以尝试在执行当前之前从其超级视图中删除消失的视图控制器视图。这应该可以防止它在转换时进行布局计算。如果这解决了性能问题,您可以quickly snapshot the view hierarchy然后将其替换为快照的单个新UIImageView,以便在过渡动画期间显示。

(最后一件事:你的单元格中是否有任何使用自动布局的表格视图?这些表格视图中的任何一个都有超过20个单元格吗?)

答案 2 :(得分:1)

当展示另一个控制器时,必须在窗口外设置原始控制器的动画,这会导致view frame更改,并可能触发所有layoutSubviews方法和你的手动调整。

您可以尝试通过停用autoresizesSubviews中的viewWillDisappear来避免这种情况。

它不是很干净,但那么你所做的所有计算可能都不是很好!

尝试优化它们:

  • 请勿直接致电layoutSubviews,仅在确实需要时致电setNeedsLayout
  • 尝试使用autoresizingMaskautoLayout替换手动调整大小代码。
  • 懒惰地调整视图,只有在视图可见且其size而非原点确实已更改时才会调整视图。
  • 不要完全重新加载您的表,但只尝试更改单个行。
  • 尝试仅使用单个表格视图。
  • 确保重复使用单元格。

答案 3 :(得分:0)

问题可能与您将UITableView实例放在UIScrollView中有关。这是Apple的documentation for UIWebView明确禁止的(惊喜!):

  

重要说明:您不应在UIScrollView对象中嵌入UIWebView或 UITableView 对象。如果这样做,可能会导致意外行为,因为两个对象的触摸事件可能会混淆和错误处理。

我怀疑也可能搞乱表视图单元重用机制。无论如何,我还建议你检查一下你是否正在泄漏'任何观点。请记住,即使不可见的视图位于视图层次结构中,也会参与布局。

编辑:响应更新2

很明显,细胞再利用机制不能正常运作。从重用队列中取出表视图单元时,请确保使用正确的UITableView实例(检查数据源)。