为什么要在 Swift 类中使用必需的初始化器?

我试图理解 required关键字在 Swift 类中的用法。

class SomeClass
{
required init() {
// initializer implementation goes here
}
}

required并不强迫我在子类中实现该方法。如果我想覆盖我的父类的 required指定的初始值设定项,我需要写 required而不是 override。我知道它是如何工作的,但不能理解为什么我应该这样做。

required的好处是什么? 据我所知,像 C # 这样的语言没有这样的东西,而且在 override中工作得很好。

37963 次浏览

根据 文件:

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

所以,是的,必需强制所有子类实现这个构造函数

 if you can satisfy the requirement with an inherited initializer.

因此,如果已经创建了不能用父构造函数完全初始化的更复杂的类,则必须实现必需构造函数。

文档中的例子(添加了一些内容) :

class SomeClass {
required init() {
// initializer implementation goes here
}
}


class SomeSubclass: SomeClass {
let thisNeedsToBeInitialized: String
required init() {
// subclass implementation of the required initializer goes here
self.thisNeedsToBeInitialized = "default value"
}
}

如果您试图在子类中添加自己的初始化器,那么您必须遵循在超类中声明的某些内容。因此,它确保您不会忘记实现所需的方法。如果您忘记了编译器会给您错误 < code >//严重错误,那么我们没有包含所需的 init () . Another reason is it creates a set of conditions that ever sub class should follow it the sub class is defining its own initialiser.

这实际上只是满足编译器的一种方式,以确保如果这个类有任何子类,它们将继承或实现相同的初始化器。在这一点上有疑问,因为规则 如果子类有自己的指定初始值设定项,则不会继承来自超类的任何初始值设定项。因此,超类可能有一个初始化器,而子类 没有有它。required克服了这种可能性。

需要以这种方式满足编译器的一种情况涉及到协议,并且是这样工作的:

protocol Flier {
init()
}
class Bird: Flier {
init() {} // compile error
}

问题是,如果 Bird 有一个子类,那么这个子类必须实现或继承 init,而您并没有保证这一点。将 Bird 的 init标记为 required确实可以保证这一点。

或者,您可以将 Bird 标记为 final,从而保证反过来,即它永远不会有子类。

另一种情况是,您有一个工厂方法,它可以通过调用相同的初始值设定项来创建一个类或其子类:

class Dog {
var name: String
init(name: String) {
self.name = name
}
}


class NoisyDog: Dog {


}


func dogMakerAndNamer(whattype: Dog.Type) -> Dog {
let d = whattype.init(name: "Fido") // compile error
return d
}

dogMakerAndNamer正在调用 Dog 或 Dog 子类上的 init(name:)初始化器。但是编译器如何确保子类具有 init(name:)初始值设定项呢?required的指定缓解了编译器的担忧。

我想提请注意由 Required提供的另一个解决方案,除了马特已经给出了上述。

class superClass{
var name: String
required init(){
// initializer implementation goes here
self.name = "Untitled"
}
}
class subClass: superClass {
var neakName: String = "Subclass Untitled"


}
let instanceSubClass = subClass()
instanceSubClass.name        //output: "Untitled"
instanceSubClass.neakName    //output: "Subclass Untitled"

正如你可以检查上面的例子,我已经在 superClass上声明了 required init(),在 subClass上默认继承了 superClass 的 init()初始化器,所以你可以创建一个子类 let instanceSubClass = subClass()的实例。

但是,假设您希望在 subClass 上添加一个指定的初始值设定项,以便将运行时值分配给存储属性 neakName。当然您可以添加它,但这将导致 没有来自 superClass 的初始化器将被继承到 subClass,因此,如果您将创建一个 subClass的实例,您将通过它自己指定的初始化程序创建,如下所示。

class superClass{
var name: String
init(){
// initializer implementation goes here
self.name = "Untitled"
}
}
class subClass: superClass {
var neakName: String = "Subclass Untitled"
init(neakName: String) {
self.neakName = neakName
}
}
let instanceSubClass = subClass(neakName: "Bobby")
instanceSubClass.name       //output: "Untitled"
instanceSubClass.neakName   //output: "Bobby"

在上面的例子中,您不能仅仅通过 subClass()但是,如果您希望 superClass 的每个子类都必须有自己的 init()初始化器来创建 subClass的实例,而是通过 subClass()来创建直接实例。只要在 superClass 上的 init()之前放置 required关键字,它就会迫使你在 subClass上也添加 init()初始化器-如下所示。

class superClass{
var name: String
required init(){
// initializer implementation goes here
self.name = "Untitled"
}
}
class subClass: superClass {
var neakName: String = "Subclass Untitled"
init(neakName: String) {
self.neakName = neakName
}
}    // Compiler error <------------ required `init()` must be provided by subClass.
let instanceSubClass = subClass(neakName: "Bobby")
instanceSubClass.name       //output: "Untitled"
instanceSubClass.neakName   //output: "Bobby"

所以,在超类初始化之前使用 required关键字,当你想要所有的子类必须已经实现了 required initializer的超类。