我有一个自定义的UIView,我使用此功能在视图控制器中实例化了该属性,displayTimer是视图控制器的iVar:

func changeViewModeTo(mode: String){

    if mode == "settings" {
        addSettingsModeConstraints()
        animatedLayoutIfNeeded(removeView: true)
    }
    if mode == "timer" {

        displayedTimer = TimerView.init()
        displayedTimer.frame = CGRect(x: (self.view.bounds.size.width)/2 - 50, y: (self.view.bounds.size.height)/2 - 80, width: 100, height: 160)

        let colors = timer.getColorScheme()
        displayedTimer.setColorScheme(colorLight: colors["lightColor"]!, colorDark: colors["darkColor"]!)
        displayedTimer.setTimeRemainingLabel(timer.duration)
        displayedTimer.setCountDownBarFromPercentage(1.0)
        displayedTimer.layer.zPosition = 100 //make sure the timer view sits on top of the settings panel
        displayedTimer.timerLabel.hidden = false
        displayedTimer.translatesAutoresizingMaskIntoConstraints = false

        let pinchGestureRecogniser = UIPinchGestureRecognizer(target: self, action: #selector(self.pinchDetected(_:)))

        displayedTimer.addGestureRecognizer(pinchGestureRecogniser)

        self.view.addSubview(displayedTimer)

        addTimerModeConstraints()
        animatedLayoutIfNeeded(removeView: false)

    }

}


如果将模式设置为计时器,则它将创建UIView的子类并为其设置实例变量,添加约束以使其全屏显示,然后调用动画layoutIfNeeded()。如果正在设置的模式是设置,则它将禁用timerConstraints,添加新的约束以缩小视图,调用动画的layoutIfNeeded,然后将视图从superView中移除。

func animatedLayoutIfNeeded(removeView removeView: Bool){
    UIView.animateWithDuration(0.2, delay: 0, options: [UIViewAnimationOptions.CurveEaseIn] , animations: {
        self.view.layoutIfNeeded()
    }) { (true) in
        if removeView == true {
            self.displayedTimer.removeFromSuperview()
        }
    }
}


使用以下方法添加和删除约束(settingsConstraints和timerConstraints是视图控制器的iVars):

//MARK: - Layout Constraints
func addSettingsModeConstraints() {

    let views = ["timerView": displayedTimer]

    let timerHorizontalConstraints = NSLayoutConstraint.constraintsWithVisualFormat(
        "H:|-75-[timerView]-75-|",
        options: [],
        metrics: nil,
        views: views)
    settingsConstraints += timerHorizontalConstraints

    let timerVerticalConstraints = NSLayoutConstraint.constraintsWithVisualFormat(
        "V:|-105-[timerView]-85-|",
        options: [],
        metrics: nil,
        views: views)
    settingsConstraints += timerVerticalConstraints

    NSLayoutConstraint.deactivateConstraints(timerConstraints)
    NSLayoutConstraint.activateConstraints(settingsConstraints)
}

func addTimerModeConstraints() {

    let views = ["timerView": displayedTimer]

    let timerHorizontalConstraints = NSLayoutConstraint.constraintsWithVisualFormat(
        "H:|-0-[timerView]-0-|",
        options: [],
        metrics: nil,
        views: views)
    timerConstraints += timerHorizontalConstraints

    let timerVerticalConstraints = NSLayoutConstraint.constraintsWithVisualFormat(
        "V:|-0-[timerView]-0-|",
        options: [],
        metrics: nil,
        views: views)
    timerConstraints += timerVerticalConstraints

    NSLayoutConstraint.activateConstraints(timerConstraints)
}


从捏手势识别器中调用changeViewModeTo(负捏设置一种模式,正捏设置另一种模式)。

我第一次捏合时,该视图已创建并进入全屏显示。然后,我反向捏合,视图缩小并被移除。然后,当我再次捏捏以通过应用程序崩溃启动该过程时,没有控制台错误,但代码行上出现红色错误:NSLayoutConstraint.activateConstraints(timerConstraints)

ios - 第二次加载UIView后,NSConstraints使应用程序崩溃-LMLPHP

我猜想删除子视图已经导致对NSConstraints的引用消失了?

我无法弄清楚任何想法。

最佳答案

因此,事实证明这是一个简单的解决方法,在重新创建并激活它们之前,先对removeAll()settingsConstraints调用timerConstraints即可解决问题。

09-30 14:17