(WWDC) 高性能AutoLayout (High Performance Auto Layout)


内容概览:

• AutoLayout在iOS 12的性能提升
• AutoLayout内部原理和直觉
• 构建高效的布局


AutoLayout在iOS 12的性能提升

灰色为iOS 11上的表现,蓝色为iOS 12上的表现。

条纹越短更好


AutoLayout内部原理与我们的直觉

假如你需要构建如下布局:



这样创建约束是不可取的,因为updateConstraints方法可能会在一秒内执行120次!


updateConstraints方法在做什么?

首先,需要介绍渲染循环(Render Loop)。也就是界面控件绘制的流程。
可以看到,渲染循环主要分为更新约束、布局、展示这三个子过程。



首先更新约束,顺序是从子视图到父视图,一直到 UIWindow,依次执行 updateConstraints() 方法。



然后是布局,顺序是从 UIWindow 开始,从父视图到子视图,依次执行 layoutSubviews() 方法。



最后是展示,顺序与布局流程相同,依次执行 draw(_ rect: CGRect) 方法。



相关的方法如下所示:

set开头的方法可以设置标记,在下一次渲染循环(Render Loop)时就会执行相应的流程。
IfNeeded结尾的方法,可以让相应的流程在当前渲染循环(Render Loop)就执行。

所以,同样地,也不要这样做!




添加 静态约束(不需要做后续的更改) 的正确方式,应该是这样:

或者,通过Xib来添加静态约束。


启用一个约束

AutoLayout内部实现原理

  1. 首先,将View放到Window上,并添加相应的约束;
  2. 布局引擎会在updateConstraints()过程中生成与约束相关的方程式;
  3. 在layoutSubviews()过程中,View会从布局引擎中取出方程式计算的结果并用于View的布局。



计算的结果,实际上就是这四个参数:minX, minY, width, height。

当约束发生变化时,布局引擎又会根据新的方程式计算新的结果,并通知View去调用父视图的setNeedsLayout()方法。


本地布局和全局布局
本地布局

全局布局(黄线对齐约束)

不相关的视图之间不要建立约束关系。
比如,上图中的text1和text3不要创建对齐的约束,这会导致AutoLayout性能下降!



添加不交互的布局时,布局的数量对布局性能的影响呈线性增长。
如果可以和直接的父视图(self.superview)或者直接父视图中的兄弟视图建立约束,就不要和其他视图建立约束,因为这样的约束性能最好。






实际上,布局引擎就是一个布局缓存和依赖记录器。

最后,后续的Instruments会增加Layout调试组件,敬请期待。
使用工具调试布局的性能问题可以让我们免于直觉的误导。


构建高效的布局

假设你需要构建如下布局:


无图状态

有图状态

单个用户头像状态



实际的效果图:



可以使用Instruments中的Layout诊断工具进行诊断:

不过,遗憾的是Xcode 10.2中并未发现此工具。可能还需要等到后续的Xcode版本才能用上。



仔细观察布局,对于控件1的布局,我们可以通过修改控件隐藏/显示属性来进行控制,所以只有控件2真正需要改变布局的约束。而控件2涉及到的约束其实并不多,通过两组约束就可以进行调控。


约束波动:
  • 避免移除所有约束;
  • 对于静态约束,只添加一次;
  • 只改变需要改变的约束;
  • 隐藏View,而不是removeFromSuperview();


intrinsicContentSize属性:
  • 不是所有的View都需要它;
  • 不以View作为内容的View:
    • UIImageView 返回image的size;
    • UILabel 返回text的size,所以长文本可能会造成性能问题;
  • UIView使用它来创建约束;
  • 选择性地重写来提高文本控件布局性能;
    • 直接返回文本的size,而不是让系统去计算文本的size;
    • 使用UIView.noIntrinsicMetric和约束;
override var intrinsicContentSize: CGSize {
    // 避免文本size的计算,让约束决定文本的size
    return CGSize(width: UIView.noIntrinsicMetric, height: UIView.noIntrinsicMetric)
}


systemLayoutSizeFitting(_ targetSize:)方法
  • 从布局引擎取出计算结果;
  • 在结合frame使用的时候,需要用到它。

在调用systemLayoutSizeFitting(_ targetSize:)方法时,具体执行流程如下:

  1. 创建布局引擎;
  2. 添加约束;
  3. 计算布局;
  4. 顶部View的Size被返回;
  5. 布局引擎被废弃;

所以,使用这个方法前需要考虑性能问题,毕竟每次调用都会创建一个新的布局引擎。





参考文章:
High Performance Auto Layout




转载请注明出处,谢谢~

你可能感兴趣的:((WWDC) 高性能AutoLayout (High Performance Auto Layout))