initializer的自動繼承
在物件繼承時,會獲得父類別的屬性以及方法,然而init卻不見得會繼承到子類別,要讓父類別的init自動被繼承需要滿足幾個條件,官方文件的說明如下:
1. If your subclass doesn’t define any designated initializers, it automatically inherits all of its superclass designated initializers.
如果子類別沒有定義任何designated initializers,他會自動繼承父類別的designed initializer。
表示當今天子類別沒有
再新增任何不含值的屬性
時,就不需要再自定義designated initializers去賦值給新的屬性,因此就可以繼承父類別的designed initializer。
以剛剛的例子示範:
class File {
var filename: String
var data: String
init(filename: String, data: Any) {
self.filename = filename
self.data = String(describing: data)
}
}
class VersionedFile:File {
var version:Double = 1
convenience init(filename: String, data: Any, version:Double){
self.init(filename: filename, data: data)
self.version = version
}
}
子類別VersionedFile
新增的屬性version
已經有預設值1
,因此不需要再自定義init,此時便可繼承父類別的所有designated initializers。由下圖可知,init(filename:data:)
是繼承自父類別的建構子。另外也可以觀察到,就算有定義convenience initializers,也不會影響繼承。
我如果在子類別自定義designated initializer,則繼承的init就會消失
class VersionedFile:File {
var version:Double = 1
//重新自定義designated initializer(新增createdDate參數)
init(filename: String, data: Any, createdDate:Double) {
super.init(filename: filename, data: data)
}
convenience init(filename: String, data: Any, version:Double){
self.init(filename: filename, data: data, createdDate: 0)
self.version = version
}
}
由圖可知,繼承的init(filename:data:)
已經被自定義的init給覆蓋掉,變成init(filename:data:version:)
。
2. If your subclass provides an implementation of all of its superclass designated initializers — either by inheriting them as per rule 1, or by providing a custom implementation as part of its definition — then it automatically inherits all of the superclass convenience initializers.
如果子類有繼承或客製化父類”所有的”designated initializers,則子類就可獲得父類的convenience initializers。
以實際例子示範,首先,先定義一個Food
類別物件,並自定義init初始化屬性。
class Food {
var name: String
init(name: String) {
self.name = name
}
convenience init() {
self.init(name: "[Unnamed]")
}
}
定義RecipeIngredient
的類別,並繼承Food
。接著自定義init來將自己的屬性quantity
賦值,最後呼叫super.init
將繼承來的屬性賦值。
class RecipeIngredient: Food {
var quantity: Int
init(name: String, quantity: Int) {
//將自己的屬性quantity賦值
self.quantity = quantity
//將將繼承來的屬性賦值
super.init(name: name)
}
接著初始化物件,看看建構子如何:
可以發現自定義init後,根據自動繼承的規則(rule 1),將無法繼承父類別的所有的initializers(designated initializers與convenience initializers)。
但如果將父類別的所有designated initializers 客製(custom implementation),便可以符合自動繼承的規則(rule 2),將可以繼承父類別的convenience initializers,如下面所示:
class RecipeIngredient: Food {
var quantity: Int
init(name: String, quantity: Int) {
self.quantity = quantity
super.init(name: name)
}
//將父類別的designated initializer進行custom implementation
override convenience init(name: String) {
self.init(name: name, quantity: 1)
}
}