iT邦幫忙

2022 iThome 鐵人賽

DAY 22
0
自我挑戰組

初入Swift新手村的旅程系列 第 22

Day22 Swift 初始化

  • 分享至 

  • xImage
  •  

初始化

Swift中的初始化要求struct和class必須要在初始化結束前完成其中儲存屬性的構造( lazy除外 )。因此開發者在設計時往往採用兩種方式。

  • 在class和struct終須告儲存屬性時直接將其設置為初始默認值
  • 在class和struct的構造方法中對儲存屬性中進行構造或者設置默認值
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關鍵字來修飾

  • 子類的指定構造方法中必須調用父類的指定構造方法
  • 便利構造方法中必須調用當前類的其他構造方法
  • 必練構造方法要調用某個指定構造方法
    如下圖

https://ithelp.ithome.com.tw/upload/images/20221007/20152549KEEfxY9O4a.png

// 建立一個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()
    }
}

接下來,是反初始化的介紹


上一篇
Day21 Swift 下標
下一篇
Day23 Swift 反初始化
系列文
初入Swift新手村的旅程30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言