最近在使用snapkit布局时,竟然发现更新约束会导致崩溃,为什么这样呢?
- checkButton.snp.makeConstraints { (make) in
- make.left.top.equalToSuperview()
- make.height.equalTo(radioListSubviewButtonHeight)
- make.width.equalTo(self).multipliedBy(0.5)
- }
- checkButton.snp.updateConstraints { (make) in
- make.width.equalTo(self).multipliedBy(0.7)
- }
看起来完全没有问题,但是一运行就崩溃,崩溃位置在activeIfNeeded方法中:
- internal func activateIfNeeded(updatingExisting: Bool = false) {
- guard let item = self.from.layoutConstraintItem else {
- print("WARNING: SnapKit failed to get from item from constraint. Activate will be a no-op.")
- return
- }
- let layoutConstraints = self.layoutConstraints
- if updatingExisting {
- var existingLayoutConstraints: [LayoutConstraint] = []
- for constraint in item.constraints {
- existingLayoutConstraints += constraint.layoutConstraints
- }
- for layoutConstraint in layoutConstraints {
- let existingLayoutConstraint = existingLayoutConstraints.first { $0 == layoutConstraint }
- guard let updateLayoutConstraint = existingLayoutConstraint else {
- fatalError("Updated constraint could not find existing matching constraint to update: \(layoutConstraint)")
- }
- let updateLayoutAttribute = (updateLayoutConstraint.secondAttribute == .notAnAttribute) ? updateLayoutConstraint.firstAttribute : updateLayoutConstraint.secondAttribute
- updateLayoutConstraint.constant = self.constant.constraintConstantTargetValueFor(layoutAttribute: updateLayoutAttribute)
- }
- } else {
- NSLayoutConstraint.activate(layoutConstraints)
- item.add(constraints: [self])
- }
- }
fatalerror信息提示找不到因存在的constraint来更新,输出existingLayoutConstraints不为nil,输出existingLayoutConstraint却为nil,很奇怪。
点击进入first方法,发现是取第一个满足谓词条件的值,而不是简单的取第一个值:
- /// Returns the first element of the sequence that satisfies the given
- /// predicate.
- ///
- /// The following example uses the `first(where:)` method to find the first
- /// negative number in an array of integers:
- ///
- /// let numbers = [3, 7, 4, -2, 9, -6, 10, 1]
- /// if let firstNegative = numbers.first(where: { $0 < 0 }) {
- /// print("The first negative number is \(firstNegative).")
- /// }
- /// // Prints "The first negative number is -2."
- ///
- /// - Parameter predicate: A closure that takes an element of the sequence as
- /// its argument and returns a Boolean value indicating whether the
- /// element is a match.
- /// - Returns: The first element of the sequence that satisfies `predicate`,
- /// or `nil` if there is no element that satisfies `predicate`.
- ///
- /// - Complexity: O(*n*), where *n* is the length of the sequence.
- public func first(where predicate: (Element) throws -> Bool) rethrows -> Element?
在此处谓词条件为 $0 == layoutConstraint ,进入LayoutConstraint类中,发现==运算符已被重载:
- internal func ==(lhs: LayoutConstraint, rhs: LayoutConstraint) -> Bool {
- guard lhs.firstItem === rhs.firstItem &&
- lhs.secondItem === rhs.secondItem &&
- lhs.firstAttribute == rhs.firstAttribute &&
- lhs.secondAttribute == rhs.secondAttribute &&
- lhs.relation == rhs.relation &&
- lhs.priority == rhs.priority &&
- lhs.multiplier == rhs.multiplier else {
- return false
- }
- return true
- }
在判断相等时,竟然还判断了multiplier,本例中更新约束前后multiplier不相等,所以找不到对应的约束。
解决方法:
要想修改multiplier,不能使用update,要使用remake
snapkit issue中相似问题