snapkit更新約束崩潰的問題

最近在使用snapkit佈局時,居然發現更新約束會致使崩潰,爲何這樣呢? git

        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方法中:github

    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方法,發現是取第一個知足謂詞條件的值,而不是簡單的取第一個值:spa

    /// 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類中,發現==運算符已被重載:code

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不相等,因此找不到對應的約束。blog

 

解決方法:ip

要想修改multiplier,不能使用update,要使用remakeelement

snapkit issue中類似問題rem

相關文章
相關標籤/搜索