考虑两个类:
class A {
var x: Int
init(x: Int) {
self.x = x
}
convenience init() {
self.init(x: 0)
}
}
class B: A {
init() {
super.init() // Error: Must call a designated initializer of the superclass 'A'
}
}
我不明白为什么不允许这样做。最终,每个类的指定初始值设定项都会调用它们需要的任何值,所以为什么我需要在B
的{{1}}中重复一次,方法是再次为init
指定一个默认值。 x
中的便利init
会不会很好?
答案 0 :(得分:25)
这是Swift编程指南中规定的“初始化链接”规则的规则1,其中包括:
规则1:指定的初始值设定项必须从其中调用指定的初始值设定项 直接超类。
强调我的。指定的初始化程序不能调用便利初始化程序。
有一个图表与规则一起展示了允许初始化程序“方向”:
答案 1 :(得分:21)
考虑
class A
{
var a: Int
var b: Int
init (a: Int, b: Int) {
print("Entering A.init(a,b)")
self.a = a; self.b = b
}
convenience init(a: Int) {
print("Entering A.init(a)")
self.init(a: a, b: 0)
}
convenience init() {
print("Entering A.init()")
self.init(a:0)
}
}
class B : A
{
var c: Int
override init(a: Int, b: Int)
{
print("Entering B.init(a,b)")
self.c = 0; super.init(a: a, b: b)
}
}
var b = B()
因为A类的所有指定初始化器都被重写,所以B类将继承A的所有便利初始化器。因此执行它将输出
Entering A.init()
Entering A.init(a:)
Entering B.init(a:,b:)
Entering A.init(a:,b:)
现在,如果指定的初始化器B.init(a:b :)将被允许调用基类便捷初始化器A.init(a :),这将导致对B.init的递归调用(a: ,b:)
答案 2 :(得分:12)
这是因为你最终可以得到无限递归。考虑:
class SuperClass {
init() {
}
convenience init(value: Int) {
// calls init() of the current class
// so init() for SubClass if the instance
// is a SubClass
self.init()
}
}
class SubClass : SuperClass {
override init() {
super.init(value: 10)
}
}
并查看:
let a = SubClass()
会拨打SubClass.init()
,呼叫SuperClass.init(value:)
,呼叫SubClass.init()
。
指定/便利初始化规则被设计为类初始化始终是正确的。
答案 3 :(得分:1)
我为此找到了解决方法。它不是非常漂亮,但它解决了不知道超类的值或想要设置默认值的问题。
您所要做的就是使用方便init
创建超类的实例,就在子类的init
中。然后使用刚刚创建的实例调用super的指定init
。
class A {
var x: Int
init(x: Int) {
self.x = x
}
convenience init() {
self.init(x: 0)
}
}
class B: A {
init() {
// calls A's convenience init, gets instance of A with default x value
let intermediate = A()
super.init(x: intermediate.x)
}
}
答案 4 :(得分:1)
考虑从方便的init()
中提取初始化代码到新的辅助函数foo()
,调用foo(...)
在子类中进行初始化。
答案 5 :(得分:0)
观看WWDC-video" 403中间Swift"在18:30深入解释初始化器及其继承。据我了解,请考虑以下事项:
class Dragon {
var legs: Int
var isFlying: Bool
init(legs: Int, isFlying: Bool) {
self.legs = legs
self.isFlying = isFlying
}
convenience initWyvern() {
self.init(legs: 2, isFlying: true)
}
}
但现在考虑一个Wyrm子类: 龙是龙,没有腿,没有翅膀。所以Wyvern的初始化器(2条腿,2个机翼)是错误的!如果不能简单地调用方便的Wyvern-Initializer,而只能调用完整的指定初始化程序,则可以避免该错误:
class Wyrm: Dragon {
init() {
super.init(legs: 0, isFlying: false)
}
}
答案 6 :(得分:-1)
为什么你没有两个初始值设定项 - 一个具有默认值?
class A {
var x: Int
init(x: Int) {
self.x = x
}
init() {
self.x = 0
}
}
class B: A {
override init() {
super.init()
// Do something else
}
}
let s = B()
s.x // 0