为什么 NSLayoutConstraint 是可选类型?

Why NSLayoutConstraint is optional type?

通常我会避免在Whosebug上在这里问一个新问题,因为90%的问题都可以通过搜索轻松解决。但有时你不能这样做。

我有几个对象 class GameTimer : UIView 添加到数组中 var timersArray: [GameTimer?] { get set } 我的视图控制器动态。 我已经实现了一些小的 class 来处理该对象的约束。每次添加新对象时,我也会添加纵向和横向模式的约束。

class ConstraintsContainer {

    var portraitConstraints: [NSLayoutConstraint] = []
    var landscapeConstraints: [NSLayoutConstraint] = []

func setGeneralConstraints(timerView: GameTimer?, timerViewSize: CGFloat) {
    timerView?.translatesAutoresizingMaskIntoConstraints = false
    timerView?.heightAnchor.constraint(equalToConstant: timerViewSize).isActive = true
    timerView?.widthAnchor.constraint(equalToConstant: timerViewSize).isActive = true
    print("General constraints")
}

func getDeviceOrientation() {

        if UIDevice.current.orientation == UIDeviceOrientation.portrait || UIDevice.current.orientation == UIDeviceOrientation.portraitUpsideDown {
            NSLayoutConstraint.activate(portraitConstraints)
        } else {
            NSLayoutConstraint.activate(landscapeConstraints)
        }
    }
}

当我尝试在我的视图控制器中使用这个class时

var constraintsContainer = ConstraintsContainer()

并为实例设置一些值

constraintsContainer.portraitConstraints = [
            timersArray[0]?.topAnchor.constraint(equalTo:    view.topAnchor, constant: view.frame.height/4.5),
            (timersArray[0]?.centerXAnchor.constraint(equalTo: view.centerXAnchor))
        ]

        constraintsContainer.landscapeConstraints = [
            (timersArray[0]?.topAnchor.constraint(equalTo: view.topAnchor, constant: view.frame.height/6.5)),
            (timersArray[0]?.centerXAnchor.constraint(equalTo: view.centerXAnchor))
        ]

我收到来自 XCode 的错误警告,告诉我 "value of optional type 'NSLayoutConstraint?' is not unwrapped" 并建议我像这样解开每个约束 (timersArray[0]?.topAnchor.constraint(equalTo: view.topAnchor, constant: view.frame.height/4.5))!

因此,考虑到它是引用 class NSLayoutConstraint : NSObject,无法理解为什么 NSLayoutConstraint 类型在这里显示为可选。 是否有可能避免它成为可选的?原因 - 当我停用特定对象的约束,然后从 constraintsContainer 中清除约束并从 timersArray 中删除我的 GameTimer class 类型的对象并实现此解包时,我发现了一个错误 -

Thread 1:EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)

 func deactivate() {

    NSLayoutConstraint.deactivate(constraintsContainer.portraitConstraints)
    NSLayoutConstraint.deactivate(constraintsContainer.landscapeConstraints)
    constraintsContainer.portraitConstraints.removeAll()
    constraintsContainer.landscapeConstraints.removeAll()
}

为什么 NSLayoutConstraint 在我的特定情况下似乎是可选的?

查询、调用属性、下标和方法的过程可能是 'nil' 被定义为可选链接。可选链接 return 两个值 -

if the optional contains a 'value' then calling its related property, methods and subscripts returns values.

if the optional contains a 'nil' value all its its related property, methods and subscripts returns nil.

由于对方法、属性和下标的多次查询被组合在一起,一个链的失败将影响整个链并导致 'nil' 值。

并且您的 timersArray 是可选的?