天天看點

swift之初始化一、初始化

初始化

  • 一、初始化
    • 1.1-初始化器
    • 1.2-初始化器的互相調用
    • 1.3-兩段式初始化
    • 1.4-安全檢查
    • 1.5-重寫
    • 1.6-自動繼承
    • 1.7-required
    • 1.8-屬性觀察器
    • 1.9-可失敗初始化器
    • 1.10-反初始化器

一、初始化

1.1-初始化器

/*
類、結構、枚舉都可以定義初始化器
類初始化器有兩種:指定初始化器designated initializer、便捷初始化器convenience initializer
每個類至少有一個指定初始化器,指定初始化器是類的主要初始化器
預設初始化器總是類的指定初始化器(編譯器預設會生成init(){})
類偏向于少量指定初始化器,一個類通常隻有一個指定初始化器
*/
class Person{
    var height:Int=0
    var weight:Int=0
    init(){
        //指定初始化器
    }
    init(weight:Int){
        self.weight=weight
    }
    init(height:Int){
        self.height=height
    }
    convenience init(weight:Int,height:Int){
        self.init()//便捷初始化器必須實作指定初始化器
        self.weight=weight
        self.height=height
    }
}
var p1 = Person()
var p2 = Person(weight: 120)
var p3 = Person(height: 170)
var p4 = Person(weight: 140, height: 180)


           

1.2-初始化器的互相調用

/*
初始化器的互相調用規則:
	1、指定初始化器必須從它的直系父類調用指定初始化器
	2、便捷初始化器必須從相同的類裡調用另一個初始化器
	3、便捷初始化器最終必須調用一個指定初始化器
保證了使用使用任意初始化器都可以完整地初始化執行個體

*/
           
swift之初始化一、初始化

1.3-兩段式初始化

/*
為了保證初始化過程的安全,設定了兩段式初始化和安全檢查
第一階段:初始化所有屬性
	1、外層調用指定、便捷初始化器
	2、配置設定記憶體給執行個體,但未初始化
	3、指定初始化器確定目前類定義的存儲屬性都初始化
	4、指定初始化器調用父類的初始化器,不斷向上調用,形成初始化鍊
第二階段:設定新的存儲屬性
	1、從頂部初始化器往下,鍊中的每一個指定初始化器都有機會進一步定制執行個體
	2、初始化器現在能夠使用self(通路、修改它的屬性,調用它的執行個體方法等等)
	3、最終,鍊中任何便捷初始化器都有機會定制執行個體以及使用self
	
第一階段完才能用self,先試自下而上初始化屬性再是自上而下定制化執行個體
*/
class Person{
    var age:Int
    init(age:Int){
        self.age=age
    }
    convenience init(){
        self.init(age:1)
    }
}
class Child:Person{
    var name:String
    init(age:Int,name:String){
        self.name = name //調用父類初始化器前先确定自己的屬性
        super.init(age:age)
    }
}
var c = Child(age:1,name:"sw")

           

1.4-安全檢查

/*
指定初始化器必須保證在調用父類初始化器之前,其所在類定義的所有存儲屬性都要初始化完成
指定初始化器必須先調用父類初始化器,然後才能為繼承的屬性設定新值
便捷初始化器必須先調用同類中的其它初始化器,然後再為任意屬性設定新值
初始化器在第1階段初始化完成之前,不能調用任何執行個體方法、不能讀取任何執行個體屬性的值,也不能引用self 
直到第1階段結束,執行個體才算完全合法
*/


           

1.5-重寫

/*
當重寫父類的指定初始化器時,必須加上override(即使子類的實作是便捷初始化器)
如果子類寫了一個比對父類便捷初始化器的初始化器,不用加上override,因為父類的便捷初始化器永遠不會通過子類直接調用,是以,嚴格來說,子類無法重寫父類的便捷初始化器
便捷初始化器隻能橫向調用,不能被子類調用
*/

class Person{
    var age:Int
    init(age:Int){
        self.age=age
    }
    convenience init(){
        self.init(age:1)
    }
}
class Child:Person{    
    override init(age:Int){
        super.init(age:age)
    }
}



class Person{
    var age:Int
    init(age:Int){
        self.age=age
    }
    convenience init(){
        self.init(age:1)
    }
}
class Child:Person{
    var name:String
    init(age:Int,name:String){
        self.name = name
        super.init(age:age)
    }
    convenience init(){ //省略override
        self.init(age:1,name:"sw")
    }
}

           

1.6-自動繼承

/*
1、如果子類沒有自定義任何指定初始化器,它會自動繼承父類所有的指定初始化器 
2、如果子類提供了父類所有指定初始化器的實作(要麼通過方式1繼承,要麼重寫)子類自動繼承所有的父類便捷初始化器
3、就算子類添加了更多的便捷初始化器,這些規則仍然适用
4、子類以便捷初始化器的形式重寫父類的指定初始化器,也可以作為滿足規則2的一部分
*/

class Person{
    var age:Int
    var name:String
    init(age:Int,name:String){
        self.name=name
        self.age=age
    }
    init(age:Int){
        self.age=age
        self.name="sw"
    }
}
class Child:Person{
    
}
var c1=Child(age:1)
var c2=Child(age:1,name: "Maria")

           

1.7-required

/*
用required修飾指定初始化器,表明其所有子類都必須實作該初始化器(通過繼承或者重寫實作)
如果子類重寫了required初始化器,也必須加上required,不用加override

*/
//'required' modifier must be present on all overrides of a required initializer
required init(age:Int){
	//…
}
class Child:Person{
    init(age:Int){
        super.age=age
    }
}

class Person{
    init(age:Int){
    }
    
    required init(){
    }
}
class Child:Person{
    required init(){
        super.init()
    }
}

           

1.8-屬性觀察器

/*
父類的屬性在它自己的初始化器中指派不會觸發屬性觀察器,但在子類的初始化器中指派會觸發屬性觀察器
*/
class Person{
    var age:Int{
        willSet{
            print("Person.willSet",newValue)
        }
        didSet{
            print("Person.didSet",oldValue,age)
        }
    }
    init() {
        self.age=1
    }
}
class Child:Person{
    override init(){
        super.init()
        self.age=18
    }
}
var c = Child()//子類觸發了屬性觀察器,父類init()不會觸發
Person.willSet 18
Person.didSet 1 18

           

1.9-可失敗初始化器

/*
類、結構體、枚舉都可以使用init?定義可失敗初始化器
之前接觸過的可失敗初始化器

不允許同時定義參數标簽、參數個數、參數類型相同的可失敗初始化器和非可失敗初始化器
可以用init!定義隐式解包的可失敗初始化器
可失敗初始化器可以調用非可失敗初始化器,非可失敗初始化器調用可失敗初始化器需要進行解包
如果初始化器調用一個可失敗初始化器導緻初始化失敗,那麼整個初始化過程都失敗,并且之後的代碼都停止執行
可以用一個非可失敗初始化器重寫一個可失敗初始化器,但反過來是不行的

*/

class Person{
    var name:String
    init?(name:String){
        if name.isEmpty{
            return nil
        }
        self.name=name
    }
    convenience init?(){
        self.init(name:"") //一旦失敗初始化失敗
        self.name="sw"
        //...
    }
}
var p = Person()
print(p.name) //報錯

//枚舉、類型轉換器就是可失敗初始化器
 @inlinable public init?(_ description: String)
var test = Int("t")
print(test)
nil

enum Test:Int {
    case test1,test2
}
var t = Test(rawValue: 3)
print(t)
nil
           

1.10-反初始化器

/*
析構函數
deinit叫做反初始化器,類似于C++的析構函數、OC中的dealloc方法;當類的執行個體對象被釋放記憶體時,就會調用執行個體對象的deinit方法
deinit不接受任何參數,不能寫小括号,不能自行調用
父類的deinit能被子類繼承
子類的deinit實作執行完畢後會調用父類的deinit
*/

class Person{
    deinit {
        print("Person class dead.")
    }
}
var p:Person?=Person()
p=nil
Person class dead.