Swift 構造器(init)

前言:前段時間想為系統類extension一些init方法,編譯器報錯不能為該類添加指定指定構造器,并讓我在init前添加convenience,生成便利構造器。以此坑為契機,我對Swift的構造過程進行了一些了解。謹以此文記錄我對Swift構造器的理解。

說明:本文提及的構造器為類構造器,不涉及值構造器。

作用:

為自身和繼承來的存儲屬性賦初值。

構造器:

指定構造器:

類中必備的構造器,必須將類中的存儲屬性設置好值,必須至少有一個。有些子類可能不需要顯示聲明,默認繼承基類的指定構造器。
其語法為 :

init(參數名:參數類型) {
    // 構造器的實現
}

便利構造器:

輔助構造器,通過調用指定構造器為屬性賦值,便利構造器不能和指定構造器方法同名、用 convenience 關鍵字聲明。
其語法為:

convenience  init(參數名:參數類型) {
    // 構造器的實現
}

可失敗構造器

一個類在構造過程中有可能失敗,則為其定義一個可失敗構造器。一個類可定義多個可失敗構造器,其語法為:

init?(參數名:參數類型) {
    // 構造器的實現
}

//-------參考代碼:
class Person {
    var name: String
    
    var age: Int = 10
    
    // MARK -- 指定構造器
    init(name: String, age: Int) {
        self.name = name
        self.age = age
    }
    // MARK -- 便利構造器
    convenience init() {
        self.init(name: "jamalping", age: 11)
    }
    
    // MARK -- 可失敗構造器
    init?(age: Int) {
        guard age > 0 else {
            return nil
        }
        self.age = age
        self.name = "jamalping"
    }
}
print(Person.init(age: -1) ?? "Person 初始化失敗") // 輸出為:Person 初始化失敗

必要構造器

在類的構造器前添加required修飾符表明所有該類的子類都必須實現該構造器:
其語法為:

required init(參數名:參數類型) {
    // 構造器的實現
}

兩段式構造過程

一、1.確保當前類和父類所有存儲屬性都被初始化。
二、做一些其它初始化操作。

好處: 1.可以防止屬性在被初始化之前訪問, 2.可以防止屬性被另外一個構造器意外賦值
注意:構造器的初始化永遠是在所有類的第一階段初始化完畢之后才會開始第二階段

如下:

//-------參考代碼:
class Man: Person {
    var weight: Int
    init(weight: Int) {
        print("初始化第一階段開始")
        self.weight = weight
        // 對父類的屬性進行初始化
        super.init(name: "jamalping", age: 33)
        print("初始化第二階段開始")
        if self.age > 30 {
            self.name = "jamal"
        }
    }
}
Man.init(weight: 100).name // 輸出結果為jamal```
##構造器鏈(指定構造器與便利構造器間的調用關系)
######規則:
1、指定構造器必須調用父類的指定構造器。
2、便利構造器必須調用同一類中其他的構造器。
3、便利構造器必須以調用一個指定構造器結束。
**總結**:指定構造器是向上調用的,便利構造器是橫向調用的。
//-------參考代碼:
class Person1 : Person {
    var age: Int
    var weight: Int = 100
    init(age: Int) {
        // 先初始化存儲屬性、再調用父類的指定構造器
        self.age = age
        super.init(name: "jamalping")
    }
    
    convenience init(age: Int, weight: Int) {
        // 先調用指定構造器初始化self、再初始化其他屬性
        self.init(weight: weight)
        self.age = age
    }
    
    convenience init(weight: Int) {
        self.init(age: 22, weight: weight)
    }
}

構造器的繼承

Swift的子類不會默認繼承父類的構造器,滿足以下條件之一會自動繼承
1、子類沒有定義指定構造器
2、子類實現了父類的所有指定構造器
如下:兩種情況都滿足條件,所以子類自動繼承了父類的構造器

//-------參考代碼:
class Man: Person {
    // 沒有定義指定構造器
}

class Women: Person {
    //實現了父類的所有指定構造器 
    override init(name: String) {
        super.init(name: name)
    }
}

Man.init().name  // name為"jamalping"
Women().name  // name為"jamalping"

構造器的重寫

其語法為:

override init(參數名:參數類型) {
    // 構造器的實現
}
class Man1: Person {
    
    // 指定構造器的重寫
    // 如果子類中的構造器和父類一模一樣, 必須加上override關鍵字, 表示重寫父類方法
//    override init(name: String, age: Int) {
//        super.init(name: name, age: age)
//        self.name = "super man"
//    }
    
    // 將父類的指定構造器重寫成一個便利構造器, 也必須加上override關鍵字, 表示重寫父類方法
    override convenience init(name: String, age: Int) {
        self.init(name: name, age: age)
    }
    // 將父類的可失敗構造器重寫成指定構造器
//    override init(age: Int) {
//        super.init(name: "jamalping", age: age)
//    }
    
    // 將父類的可失敗構造器重寫成便利構造器
    override convenience init(age: Int) {
        self.init(name: "jamalping", age: age)
    }
}
注意:

便利構造器不存在重寫
extension一個類的構造器,只能extension便利構造器

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 本章將會介紹 存儲屬性的初始賦值自定義構造過程默認構造器值類型的構造器代理類的繼承和構造過程可失敗構造器必要構造器...
    寒橋閱讀 778評論 0 0
  • 123.繼承 一個類可以從另外一個類繼承方法,屬性和其他特征。當一個類繼承另外一個類時, 繼承類叫子類, 被繼承的...
    無灃閱讀 1,423評論 2 4
  • 構造過程是使用類、結構體或枚舉類型的實例之前的準備過程。在新實例可用前必須執行這個過程,具體操作包括設置實例中每個...
    莽原奔馬668閱讀 699評論 0 3
  • 構造過程 構造過程是使用類、結構體或枚舉類型的實例之前的準備過程。在新實例可用前必須執行這個過程,具體操作包括設置...
    蠱毒_閱讀 738評論 0 2
  • 卿似臨水照花人 ——“花說”紅樓女子 一曲紅樓幽夢,唱的是繁華一場,唱的是風流佳事。中有美女如云,然又各有各的特色...
    蒼洱_閱讀 1,454評論 1 8