为什么在Swift类中使用必需的Initializers?

时间:2015-05-06 18:54:18

标签: swift initialization

我试图了解在Swift类中使用required关键字。

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

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

required有什么好处? 据我所知,像C#这样的语言没有这样的东西,并且可以与override一起使用。

4 个答案:

答案 0 :(得分:78)

它实际上只是满足编译器的一种方式,以确保如果这个类有任何子类,它们将继承或实现相同的初始化程序。在这一点上存在疑问,因为规则如果子类具有自己的指定初始化器,则不会继承超类中的初始化器。因此,超类可能有一个初始化程序,而子类可以拥有它。 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指定可以平息编译器的恐惧。

答案 1 :(得分:6)

除了马特上面给出的内容之外,我想提请注意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"

正如您在上面的示例中所述,我已在required init()上声明superClassinit() superClass的初始化程序默认在subClass上继承,所以你能够创建子类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创建subClass()的实例,但是如果您希望superClass的每个子类都必须拥有自己的init() } initializer 通过subClass()创建直接实例。只需在required之前将init()关键字放在superClass上,它就会强制您在init()上添加subClass初始化程序 - 如下所示。

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时。

答案 2 :(得分:5)

根据documentation

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.

因此,如果您创建了无法使用父构造函数完全初始化的更复杂的类,则必须实现require构造函数。

文档示例(添加了一些内容):

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

答案 3 :(得分:0)

如果您尝试在子类中添加自己的初始化器,那么您必须遵循在超类中声明的某些事物。因此,它确保您不会忘记实现所需的方法。如果你忘了编译器会给你错误// fatal error, we've not included the required init() 。另一个原因是它创建了一组条件,子类应该遵循它,子类正在定义它自己的初始化器。