最近在使用snapkit佈局時,竟然發現更新約束會導致崩潰,為什麼這樣呢? 看起來完全沒有問題,但是一運行就崩潰,崩潰位置在activeIfNeeded方法中: fatalerror信息提示找不到因存在的constraint來更新,輸出existingLayoutConstraints不為nil,輸 ...
最近在使用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