4

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

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

class PureViewController : UIViewController {

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

}

但这不行,因为 XCode 告诉我我还必须实现init(coder aDecoder: NSCoder). 好的,没关系!这就是我制作这个类的原因——所以我不必为子类再做一次。

class PureViewController : UIViewController {

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

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

}

好的,现在这是我不明白的。

我定义了一个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")
    }

}

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

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

我的问题如下:

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

3 回答 3

2

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

让我们假设一个基类

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 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,这是您的决定 - 但不要指望语言在这方面支持您。

于 2015-08-06T23:56:31.080 回答
1

我认为这是一个快速的问题,没有办法避免这种情况。我们都讨厌这个空的——致命的错误初始化器。

于 2015-08-06T22:48:39.310 回答
1

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

必需的初始化程序

在类初始化器的定义之前写 required 修饰符,表示该类的每个子类都必须实现该初始化器

您还必须在所需初始化程序的每个子类实现之前编写 required 修饰符,以指示初始化程序要求适用于链中的其他子类。”</p>

自 1.0 以来,这一直是 Swift 语言的一部分,并且不太可能改变。

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

于 2015-08-06T22:55:18.277 回答