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


内容概览:

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


AutoLayout在iOS 12的性能提升

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

1306450-744fec1a1ba4bb58.png
条纹越短更好


AutoLayout内部原理与我们的直觉

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

1306450-5d4bfaad611ec761.png



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

1306450-f2ec7cc5b5b8dac3.png


updateConstraints方法在做什么?

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

1306450-44e6ac6adb1635b5.png



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

1306450-eb35824c39494430.png



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

1306450-b7d145b617466e3a.png



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

1306450-df230b1d7372e102.png



相关的方法如下所示:

1306450-c780d539f2a80624.png

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

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


1306450-31f1f12c19e8d0a5.png



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

1306450-bc44d59e935b10e5.png

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


启用一个约束

AutoLayout内部实现原理

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



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

1306450-232ca7a6add9f8ab.png

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


本地布局和全局布局
1306450-71673d11da4d0a8d.png
本地布局

1306450-360f97360200f380.png
全局布局(黄线对齐约束)

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



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

1306450-1ad845c78fc3bdf8.png

1306450-a8b4d322e8151236.png

1306450-c94916920713f715.png

1306450-479d8e022d294d17.png



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

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


构建高效的布局

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


1306450-ae4fabe1f111cc17.png
无图状态

1306450-56bc7ac369bc934c.png
有图状态

1306450-6e6daafd1c4a9906.png
单个用户头像状态



实际的效果图:

1306450-8a1db2d77a6b37fe.png



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

1306450-506053e1b795d4e2.png

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



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

1306450-9bd3b158afb18f1d.png

1306450-20b1ee43b349d7e0.png


约束波动:
  • 避免移除所有约束;
  • 对于静态约束,只添加一次;
  • 只改变需要改变的约束;
  • 隐藏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




转载请注明出处,谢谢~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值