隐式解包和初始化器

Implicit Unwrapping and Initializers

我有一个UIView的子类,它实例化了几个子层。为了方便起见,我特别想要一个直接引用,因为它与视图具有相同的生命周期,所以将它设为 let 常量似乎是合理的。问题是我希望子层对其 owner/parent 视图有一个类似的不可变引用,所以我尝试将其传递给层的初始化程序:

class MyView: UIView{
    let myLayer: MyLayer!

    required init?(coder aDecoder: NSCoder){ 
        super.init(coder: aDecoder)
        self.myLayer = MyLayer(owner: self)   //  <- The problem line.
        self.layer.addSublayer(self.myLayer)
    }
}

class MyLayer: CAShapeLayer {
    unowned let owner: MyView

    init(owner: MyView) {
        self.owner = owner
        super.init ()   
    }
 }

如果我在调用 MyViewsuper.init 之前调用层初始值设定项,我会得到错误 “'self' used before 'super.init' call.” 我认为这是允许的(首选我总是想?)在 属性 初始化中使用 self,但它还没有可以作为参数传递的值?

但是如果我把这一行放在 super.init 之后,如图所示,我会得到两个错误:“Property 'self.myLayer' not initialized at super.init call”“Immutable value 'self.myLayer' may only be initialized once.” 这让我很困惑,因为我认为隐式解包可选的一点是它的声明中有一个有效的 nil 值,并且这不算作 let 语句允许的唯一赋值。 (这听起来也有点矛盾:有些东西没有初始化,但在尝试初始化之后,它最终还是被初始化了两次,是吗?)

我知道我可以通过放弃对不可变的痴迷来解决这个问题,但是有没有办法正确地做到这一点?我完全赞成Swift的安全检查,但这里真的有危险吗?我认为隐式展开会向编译器发出信号,表明程序员已意识到可能存在的问题并正在寻找后果。

我认为隐式解包可选的一点是它的声明中有一个有效的 nil 值,这不算是唯一的赋值 let声明允许。

不幸的是,它很重要。此更新后此行为已修复为当前样式:

Xcode Release Notes > Xcode 6.3 > Swift Language Changes

您可能已经找到了一些解决方法,但我认为这将非常接近您想要的:

class MyView: UIView          {
    private(set) var myLayer: MyLayer!

    required init?(coder aDecoder: NSCoder)   {
        super.init(coder: aDecoder)
        self.myLayer = MyLayer(owner: self)
        self.layer.addSublayer(self.myLayer)  }
}

您可以为此使用惰性变量。它基本上是一个 let,只在第一次使用时初始化一次。

class MyView: UIView{
    lazy var myLayer: MyLayer = {
        return MyLayer(owner: self)
    }()

    required init?(coder aDecoder: NSCoder){
        super.init(coder: aDecoder)
        self.layer.addSublayer(self.myLayer) 
    }
}