隐式展开和初始化

时间:2018-07-14 21:56:21

标签: swift init super self

我有一个UIView的子类,它实例化了几个子层。为了方便起见,我特别希望直接引用一个视图,并且由于它与视图具有相同的生存期,因此使其成为常量是合理的。问题是我希望子层对其所有者/父视图具有类似的不变引用,因此我尝试将其传递给层的初始化程序:

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 ()   
    }
 }

如果我将对层初始化器的调用放在对MyView的{​​{1}}的调用之前,则会收到错误super.init,我认为这表示它是允许的(首选,我一直以为?)可以在属性初始化中使用“'self' used before 'super.init' call.”,但是还没有可以作为参数传递的值?

但是,如果我如图所示将行放置在super.init之后,则会出现两个错误:self“Property 'self.myLayer' not initialized at super.init call”这使我感到困惑,因为我认为一个隐式展开的可选项的一点是它具有来自其声明的有效“Immutable value 'self.myLayer' may only be initialized once.”值,并且该值不算作一个仅让let语句允许的赋值。 (这听起来也有些矛盾:尚未初始化,但是在尝试初始化后,它却被初始化了两次,但是?)

我知道我可以摆脱对不可变对象的迷恋,从而解决问题,但是有办法正确地做到这一点吗?我都赞成Swift进行安全检查,但是这里真的有危险吗?我认为隐式解包会向编译器发出信号,表明程序员意识到可能的问题并正在寻找后果。

2 个答案:

答案 0 :(得分:1)

我认为一个隐式展开的可选内容的一个要点是,它在声明中具有有效的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)  }
}

答案 1 :(得分:1)

您可以为此使用惰性变量。这基本上是一个让步,在首次使用的网站上只能初始化一次。

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