NSConstraints 在第二次加载 UIView 后崩溃应用程序

Posted

技术标签:

【中文标题】NSConstraints 在第二次加载 UIView 后崩溃应用程序【英文标题】:NSConstraints crashes app after second load of UIView 【发布时间】:2016-07-28 15:31:28 【问题描述】:

我有一个自定义 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 是视图控制器的 iVar):

//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)

我猜删除子视图会导致对 NSConstraints 的引用消失?

任何想法都会很棒,因为我无法弄清楚。

【问题讨论】:

【参考方案1】:

事实证明这是一个简单的解决方法,在重新创建它们并激活它们解决问题之前,在 settingsConstraintstimerConstraints 上调用 removeAll()

【讨论】:

以上是关于NSConstraints 在第二次加载 UIView 后崩溃应用程序的主要内容,如果未能解决你的问题,请参考以下文章

Swift 4:UITableViewCell 在初始加载时不会显示数据,但会在第二次加载时加载

关闭块不会在第二次 swift3 上重新加载表

SQL Reporting Services报告仅在第二次单击时加载

图像控制 ActualWidth 仅在第二次加载后才正确 - Image Cropper

如何在第二次单击时关闭 div?

为什么Ajax没有在第二次点击时填充DIV?