Swift中的初始化要求struct和class必須要在初始化結束前完成其中儲存屬性的構造( lazy除外 )。因此開發者在設計時往往採用兩種方式。
class MyClass{
// 宣告屬性時直接附值
var count: Int = 0{
willSet{
print("willset")
}
}
var name: String{
didSet{
print("didset")
}
}
// 自定義構造方法
init(){
name = "Andy"
}
}
在對儲存屬性設置默認值或者在構造方法中對其構造時,並不會觸發屬性監聽器,只有在構造完成時,再次對其賦值才會觸發。
init()方法中為不帶參數的構造方法,Swift中所有的構造方法都需要使用init來標示,開發者可以透過函數重載來建立適用於各種場景的構造方法,以及如果某個屬性在邏輯上是允許為nil的,開發者可以將其宣告為optional類型,對於optional類型的屬性,如果在構造方法中不進行賦值,則會被默認賦值為nil。
class MyClass{
// 宣告屬性時直接附值
var count: Int = 0{
willSet{
print("willset")
}
}
var name: String{
didSet{
print("didset")
}
}
var opt: Int?
// 自定義構造方法
init(){
name = "Andy"
// 沒有對opt進行操作,也沒有初始值,默認為nil
}
}
常數屬性也必須在實例構造完成前被構造完成,一旦常數屬性被賦值,則不可以再被修改,以下的會報錯。
class Myclass {
let name: String = ""
init(){
// 這裡對常數再次賦值會使編譯器報錯
name = "bob"
}
}
如果class或struct中的所有儲存屬性都有初始默認值,那麼開發者不顯示的提供任何構造方法,編譯器也會默認自動生成一個無參的構造方法,在進行類型的實例化時,構造出來的實例所有屬性的值都是默認的初始值。
class MyClass2 {
var age = 25
var name = "amy"
}
// 使用默認的init構造方法進行實例的構造
var obj = MyClass2()
// 將印出age name
print("\(obj.age) \(obj.name)")
和class不同的是,對於struct,開發者可以不實現其初始化,編譯器會默認生成一個初始化,將所有屬性作為參數。
struct MyStruct {
var age: Int = 0
var name: String
}
// 默認生成帶參數的構造方法
var st = MyStruct(age: 22, name: "aasd")
還有一個需要注意的點,如果開發者為值類型提供一個自定義的初始化,則系統默認生成的初始化將失效。
struct MyStruct {
var age: Int = 0
var name: String
init(age: Int, name: String) {
self.age = age
self.name = name
}
// 在這個構造方法中調用其他的初始化
init() {
self.init(age: 22, name: "asd")
}
}
// 使用無參數的初始化依然可以將age與name設置
var st = MyStruct()
print("\(st.age) \(st.name)")
構造方法有指定構造方法與便利構造方法之分,便利構造方法前面需要加上convience關鍵字來修飾
// 建立一個class
// 建立一個class
class BaseClass {
init(){
print("Base Designated")
}
// 提供一個便利構造方法
// 便利構造方法必須調用當前class中的其他構造方法,並最終調用指定構造方法
convenience init(param: String) {
print("BaseClass Convience")
// 進行指定構造方法的調用
self.init()
}
}
// 建立一個BaseClass的子類
class SubClass: BaseClass {
// 覆寫指定構造方法必須調用父類的指定構造方法
override init() {
super.init()
}
// 提供兩個便利構造方法
convenience init(param: String) {
self.init()
}
convenience init(param: Int) {
self.init(param: "BOB")
}
}
var obj2 = SubClass()
// 印出BaseClass Designated
在繼承關係中,如果子類沒覆寫或者重寫任何指定構造方法,則會默認子類會繼承父類所有指定構造方法。
如果子類中提供了父類所有指定構造方法,則子類會默認繼承父類的便利構造方法。
// 建立一個class
class BaseCls {
// 提供兩個指定構造方法
init(){
print("BaseCls init")
}
init(param: Int){
print("BaseCls init\(param)")
}
// 提供一個便利構造方法
convenience init(param: String) {
self.init()
}
}
// 此類不進行任何構造方法的定義,默認會繼承父類的所有構造方法
class SubClsOne: BaseCls {
<#code#>
}
// 這個類中對父類的無參init()指定構造方法進行覆寫
class SubClsTwo: BaseCls {
override init() {
super.init()
}
}
// 這個類沒有覆寫父類的構造方法,但是透過函數重載的方式定義了自己的構造方法
class SubClsThree: BaseCls {
init(param: Bool) {
super.init()
}
}
// 這個類覆寫了父類的所有指定構造方法,則會默認把父類的便利構造方法繼承下來
class SubClsFour: BaseCls {
override init(param: Int) {
super.init(param: param)
}
override init() {
super.init()
}
}
接下來,是反初始化的介紹