日常开发中,大家可能会通过修改约束的 priority 来到达布局的目的。但是,如果使用不当,便会遇到崩溃问题。

首先,看下说明文档如下:

/* If a constraint's priority level is less than UILayoutPriorityRequired, then it is optional.  Higher priority constraints are met before lower priority constraints.
 Constraint satisfaction is not all or nothing.  If a constraint 'a == b' is optional, that means we will attempt to minimize 'abs(a-b)'.
 This property may only be modified as part of initial set up or when optional.  After a constraint has been added to a view, an exception will be thrown if the priority is changed from/to NSLayoutPriorityRequired.
 */
@property UILayoutPriority priority;

总结下文档中的几点:

  1. 如果该值小于 UILayoutPriorityRequired ,那么这个约束就是可选的。
  2. 值高的比值低的优先。
  3. 约束并不是总是尽如人意的,如果一个 a == b 的优先值是可选的,结果可能是取 abs(a-b)
  4. 这个属性在两种条件下可以修改
  • 初始化时候
  • 可选约束条件下

如果一个约束已经加到了 view 对象上,在两种情况下修改该属性值会抛出异常

  • 将该值改为 NSLayoutPriorityRequired
  • 该值本来为 NSLayoutPriorityRequired ,修改为其他值

注意,上面第 4 点就是我遇到的问题,在 tableView 这种复用 cell 的视图中,就会出现修改该值频繁的情况。由于通常情况下创建的约束该属性一般都是 NSLayoutPriorityRequired, 所以,我们需要修改成低级别的来实现自己的需求。


后续补充

根据上面第四点,UILayoutPriorityRequired 只能在初始化条件下可以修改,那么什么情况下算是初始化呢?就是在布局更新之前,也就是layoutSubviews调用之前。所以,对于cell这种复用的视图,很容易会复现崩溃。那么对于 UIView 这类基本视图,会发生崩溃吗?

当然也是可以的,当某种情况下需要进行强制更新约束时,便会调用layoutIfNeeded,触发 layoutSubviews 方法导致约束更新,后续在进行UILayoutPriorityRequired的修改,便会崩溃。但是这种情况,iOS 13 不会崩溃,iOS 13 以下(iOS 12 已经测过)才会崩溃。

现在,一般开发都是基于 iOS 13,并且肯定会适配 iOS 12,所以为了避免上述情况还是要注意,如果后续需要修改priority,不要使用UILayoutPriorityRequired

就算自己可以保证不调用layoutIfNeeded, 禁不住别人不调用呀。不然后续出了问题,还不是自找麻烦。当然,这也体现出代码的健壮性。代码易懂是一方面,别人修改不会影响也是一方面。