我正在尝试了解
required
关键字在 Swift 类中的使用。
class SomeClass
{
required init() {
// initializer implementation goes here
}
}
required
并不强迫我在我的子类中实现该方法。如果我想重写父类的 required
指定初始化程序,我需要编写 required
而不是 override
。我知道它是如何工作的,但不明白为什么我应该这样做。
required
有什么好处?
据我所知,像 C# 这样的语言没有这样的东西,并且可以很好地使用 override
。
这实际上只是满足编译器的一种方式,以确保如果此类有任何子类,它们将继承或实现相同的初始值设定项。关于这一点存在疑问,因为以下规则:如果子类有自己的指定初始化器,则不会继承超类的初始化器。因此,超类可能有一个初始化器,而子类不有它。
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
确实强制所有子类实现这个构造函数。然而,这不是必需的
[...] 如果您可以使用继承的初始值设定项满足要求。
因此,如果您创建了无法使用父构造函数完全初始化的更复杂的类,则必须实现
required
构造函数。
文档中的示例(添加了一些内容):
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"
}
}
除了上面给出的 Matt 之外,我想提请注意
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()
上声明了 superClass
,超类的 init()
初始值设定项默认继承于 subClass
,因此您可以创建子类 let instanceSubClass = subClass()
的实例。
但是,假设您想在子类上添加一个指定的初始值设定项,以将运行时值分配给存储的属性
neakName
。当然您可以添加它,但这将导致超类中的初始化器不会继承到子类,因此,如果您要创建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()
初始化器 来通过 subClass()
创建直接实例
。只需将 required
关键字放在超类的 init()
之前,它就会强制您在 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"
SO,当您希望所有子类必须已实现超类的
required
时,请在超类的初始化程序之前使用required initializer
关键字。
如果您尝试在子类中添加自己的初始化程序,那么您必须遵循超类中声明的某些内容。因此,它确保您不会忘记实现所需的方法。如果你忘记了,编译器会给你错误
// fatal error, we've not included the required init()
。另一个原因是它创建了一组条件,所有子类都应该遵循它,子类正在定义自己的初始化程序。