为什么我必须为我的编程 UIViewController 子类声明相同的必需但未实现的初始化程序(编码器 aDecoder)?

Why must I keep declaring the same required but not implemented initializer for init(coder aDecoder) for my programatic UIViewController subclass?

也许只有我一个人,但我发现 swift 的某些方面……至少可以说是迟钝的。

我大部分时间不使用 Interface Builder,因为我喜欢使用 PureLayout。所以我希望制作一个 UIViewController subclass,比如说 PureViewController,它有一个方便的 init 没有参数:

class PureViewController : UIViewController {

    init() {
        super.init(nibName: nil, bundle: nil)
    }

}

但这不行,因为 XCode 告诉我我还必须实施 init(coder aDecoder: NSCoder)。好的,没关系!这就是我制作这个 class 的原因 - 所以我不必为 subclasses 再次这样做。

class PureViewController : UIViewController {

    init() {
        super.init(nibName: nil, bundle: nil)
    }

    required init(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

}

好的,这是我不明白的。

我定义了一个子class,SomePureViewController : PureViewController,带有一个初始值设定项init(viewModel:ICrackersViewModel)...

class SomePureViewController : PureViewController {

    init(viewModel:ICrackersViewModel) {
        super.init()
    }

}

但它仍然要我定义相同的愚蠢初始化程序直到王国来临!

class SomePureViewController : PureViewController {

    init(viewModel:ICrackersViewModel) {
        super.init()
    }

    required init(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

}

现在我明白了这个想法 - 我的子 class 中没有 init(decoder),即使它是在其父 class.

中定义的

也许我一直在用 UIViewController 处理这个问题,但以前从未注意到它。

我的问题如下:

  1. 是否是我做错了什么导致了这种行为?
  2. 除了继承之外还有什么方法可以避免重复自己吗?
  3. 有没有计划改变这个?

我认为这是 swift 问题,无法避免。我们都讨厌这个空的 - 致命错误初始值设定项。

由于初始化器用 required 关键字标记,所有子classes 必须实现该初始化器,并且它们还必须在实现时指定 required 以便 他们的子classes也需要实现它。

Required Initializers

Write the required modifier before the definition of a class initializer to indicate that every subclass of the class must implement that initializer

You must also write the required modifier before every subclass implementation of a required initializer, to indicate that the initializer requirement applies to further subclasses in the chain.”

这从 1.0 开始就是 Swift 语言的一部分,不太可能改变。

问题实际上与在 UIViewController class 定义中使用 required 关键字有关。从理论上讲,这可以改变,但我再次认为这不太可能。

关键是,只要知道基类型就可以初始化一个可能派生的 class。

让我们假设一个基数 class

class Base {
    let value: Int

    required init(value: Int) {
        self.value = value
    }
}

和一个函数

func instantiateWith5(cls: Base.Type) -> Base {
    return cls.init(value: 5)
}

那我们可以做

let object = instantiateWith5(Base.self)

现在如果有人定义派生class

class Derived: Base {
    let otherValue: Int

    init() {
        otherValue = 1
        super.init(value: 1)
    }

    required init(value: Int) {
        fatalError("init(value:) has not been implemented")
    }
}

我们至少可以打电话

let object2 = instantiateWith5(Derived.self)

违反了 LSP,但那是你的代码的问题,而不是语言的问题。

Swift 必须保证初始化程序使您的对象处于初始化状态,即使它们是从基础对象派生的,所以我想改变这将是一件坏事。如果您想定义一个不可反序列化的 UIViewController,从而违反 LSP,这是您的决定 - 但不要指望语言在这方面支持您。