为什么使用 NSLayoutConstraint.activate 比 .isActive = true 更有效?

Why using NSLayoutConstraint.activate is more efficient than .isActive = true?

我的问题是关于约束的创建:为什么使用 activate 方法创建一组稍后激活的约束比使用 .isActive = true 逐个激活更有效?

激活直接约束,我们基本上是在更改一个属性,一个已经在 UIView 中实例化的变量,我们正在修改:

@available(iOS 9.0, *)
open var topAnchor: NSLayoutYAxisAnchor { get }

但是定义表明使用Array效率更高:

/* Convenience method that activates each constraint in the contained array, in the same manner as setting active=YES.
This is often more efficient than activating each constraint individually. */
@available(iOS 8.0, *)
open class func activate(_ constraints: [NSLayoutConstraint])

我不知道如何创建一个已经在范围内的变量数组,然后将其传递到循环中以激活它。这比启用直接约束更有效吗?

当您有多个需要激活的约束时,如果您一个一个激活它们,AutoLayout 不知道您何时“完成”激活它们。这可能会导致它在 约束之间执行一些中间计算,其结果会因随后立即添加另一个约束而被浪费。通过立即为 AutoLayout 提供一个约束列表,它既可以确保它不会在激活之间执行 任何 中间计算,又可以更好地了解所做的更改,导致可能更准确和更高效的计算。


如果您使用像 Hopper 这样的反汇编程序在 /System/Library/PrivateFrameworks/CoreAutoLayout.framework 中闲逛,您可能(目前)会看到:

  • +[NSAutolayoutConstraint activateConstraints:] 的实现是对私有 +[NSAutolayoutConstraint _addOrRemoveConstraints:activate:]
  • 的传递
  • +[NSAutolayoutConstraint _addOrRemoveConstraints:activate:],对于每个约束,尝试获取对该约束所属的布局引擎的引用(-[NSLayoutConstraint _layoutEngine]),并且
    • 如果它属于引擎,则通过调用引擎的 -[NSISEngine withAutomaticOptimizationsDisabled:] 方法来激活或停用约束
    • 如果还不属于某个引擎,则直接激活约束

-[NSLayoutConstraint setActive:] 本身也做了大量的工作,可能会搜索它的 _nearestAncestorLayoutItem_findCommonAncestorOfItem:andItem: 以便插入到正确的位置。通过在禁用优化的上下文中执行此工作,自动布局可以避免为列表中的每个约束执行不必要的工作。


AutoLayout 必须为您的每个约束做的工作量可能使创建一个数组来临时存储它们的成本相形见绌,尽管您可以在实时应用程序中对此进行概要分析以查看它可能会花费您多少.