【发布时间】:2017-01-03 18:48:29
【问题描述】:
我对 swift 中的初始化程序有疑问。根据 Apples 的Swift3.0
- 指定初始化程序必须从其直接超类调用指定初始化程序。
- 便利构造器必须调用同一个类的另一个构造器。
- 便利构造器最终必须调用指定构造器。
现在我有两个 A 类和 B 类(A 的子类)。 A & B 都有两个具有以下结构的指定初始化器
谁能建议 B 类的指定初始化程序如何调用 A 类的初始化程序?
【问题讨论】:
我对 swift 中的初始化程序有疑问。根据 Apples 的Swift3.0
现在我有两个 A 类和 B 类(A 的子类)。 A & B 都有两个具有以下结构的指定初始化器
谁能建议 B 类的指定初始化程序如何调用 A 类的初始化程序?
【问题讨论】:
由于您在A 中有两个指定的初始值设定项,因此由于签名不同,它们是明确的,并且可以相互区分。这意味着您可以轻松地从子类B 调用A 的适当指定 初始化程序。例如,A as
class A {
var a: Int
// designated "#1"
init() {
a = 0
}
// designated "#2"
init(_ a: Int) {
self.a = a
}
// convenience initializer for A
convenience init(_ foo: String) {
print(foo)
self.init(42)
}
}
我们有,例如
class B: A {
let b: Int
// designated "sub#1"
override init() {
b = 42
super.init() // use A's designated #1
}
// designated "sub#2"
override init(_ a: Int) {
b = 24
super.init(a) // use A's designated #2
}
// non-overriding designated "#3"
init(b: Int) {
self.b = b
super.init() // use A's designated #1
}
// convenience initializer for B
convenience init(_ foo: String) {
print(foo)
self.init() // use B's designated #1
}
// you may only call designated initializers of the superclass
}
但是请注意,子类的初始化器可能只能调用其超类的指定初始化器。 the Language Guide - Initializers - Initializer Delegation for Class Types [emphasis mine] 中的规则 1 和 2 涵盖了这一点:
类类型的初始化器委托
为了简化指定和便利之间的关系 初始化器,Swift 应用以下三个规则进行委托 初始化器之间的调用:
规则 1
指定初始化器必须从它的 直接超类。
第 2 条
便利构造器必须从同一个构造器调用另一个构造器 类。
第 3 条
便利构造器最终必须调用指定的 初始化器。
所以你不能从B的便利构造器中访问A的便利构造器,并且B的指定构造器自然必须按照上面的规则1只调用A的指定构造器。
【讨论】:
A 只有一个指定初始化器,因此B 的两个指定初始化器无法选择必须调用其父类的哪个指定初始化器,因为只有一个。 如果,另一方面,超类有几个指定的初始化器,(直接)子类的指定初始化器自然可以选择这两个调用中的任何一个。回想一下,指定的初始化程序完全初始化了类(“指定的初始化程序完全初始化了该类引入的所有属性......”)。
A 的两个指定初始化程序中,从B 中的给定指定初始化程序获取调用的那个是具有来自B 的调用的匹配签名。由于我们在A 中有两个指定的初始化程序,我们知道它们必须有不同的签名(因此可以区分),否则我们会产生歧义并提示编译器错误。