必需的初始化器和指定的初始化器并不真正相关,尽管相关的关键字required
和convenience
都用于指定对子类的限制。
必需的初始化程序
必需的初始化程序保证您可以使用该初始化程序初始化类型或其任何子类型。如果您在协议中有初始化程序并且您符合该协议的某些内容,则必须使用required
(如果它是一个类),因为该协议保证该初始化程序存在于该类及其任何子类中。当您required
在类的初始化程序上使用时,这表明它的所有子类也可以使用该方法进行初始化。这意味着您还需要将该初始化程序添加到它的任何子类中。
protocol TestProtocol {
init()
}
class TestClass: TestProtocol {
required init() {
}
}
在这里,required
关键字必须存在,因为 的任何子类也TestClass
必须提供init()
(因为它们也符合TestProtocol
)。
拥有一个必需的初始化程序允许您在编译时不知道它是什么的情况下初始化一个类,这有多种原因:
let classType: TestProtocol.Type = TestClass.self
let object = classType.init()
如果您的类符合多个协议,例如每个协议都有不同的初始化程序,则还必须要求每个初始化程序:
protocol OtherProtocol {
init(thing: Int)
}
class OtherClass: TestClass, OtherProtocol {
let thing: Int
required init() { // Required from superclass/its protocol
self.thing = 0
}
required init(thing: Int) { // Required from new protocol
self.thing = thing
}
}
请注意,super.init()
在这种特殊情况下不需要添加,因为 Swift 会自动包含不带参数的调用。
在所有上述示例中,初始化器都是指定的,因为它们不包含convenience
关键字。
即使您没有任何协议,您仍然可以required
通过初始化编译时未知的类类型来使用:
class BaseClass {
let value: Int
required init(value: Int) {
self.value = value
}
}
class SubClass: BaseClass {
required init(value: Int) { // Required from superclass
super.init(value: value) // Must call desginated initialiser of superclass
}
}
let someBaseClassType: BaseClass.Type = SubClass.self
let someBaseClassInstance = someBaseClassType.init(value: 1)
指定初始化器
指定的初始化器不是便利的初始化器(即,用 标记convenience
)。指定的初始化程序必须确保类的所有属性在初始化程序完成(或调用超级初始化程序)之前都有一个值。便利初始化器只是没有这个要求,因为它们必须自己调用指定的初始化器。
class OtherSubClass: BaseClass {
convenience required init(value: Int) {
self.init() // Must call designated initialiser of this class
}
init() {
super.init(value: 0) // Must call designated initialiser of superclass
}
}
(这是一个相当人为的例子。)
根据我的经验,便利初始化器很少有用,我倾向于发现它们解决的问题可以使用指定初始化器上的可选参数来解决。还需要考虑一个事实,即初始化程序不能在其超类上调用便利初始化程序,因此请确保您没有任何便利初始化程序提供您指定的初始化程序所不具备的功能,如果您希望您的类被子类化!
结构体和枚举不使用required
orconvenience
关键字,因为这些关键字都用来表示子类的初始化规则,只有class
es 支持:required
关键字表示子类必须提供那个初始化器,convenience
关键字表示子类不能调用那个初始化器。尽管没有关键字,但它们仍然必须提供在它们符合的任何协议中定义的初始化程序,并且您可以编写调用 的“方便”初始化程序,self.init
而无需convenience
关键字。
回应您的陈述:
- 不必指定所需的初始化程序。
- 不一定需要指定的初始化程序。
- 类可以有多个必需的和指定的初始化器。