Swift的 convenience && designated init


http://www.th7.cn/Program/IOS/201603/789227.shtml

 

在 OC 中 init 方法是非常不安全的,沒人能夠保證 init 只被調用一次,也沒有人保證在初始化方法調用以后實例的各個變量都完成初始化,甚至如果在初始化里使用屬性進行設置的的話,還可能會造成各種問題。Swift 強化了 designated 初始化方法的地位。swift 中不加修飾的 init 方法都需要在方法中保證所有非 Optional 得實例變量被賦值初始化,而在子類中也強制(顯示或隱式的)調用 super 版本的 designated 初始化,所以無論怎樣被初始化的對象總是可以完成完整的初始化的。

class ClassA {   
    let numA: Int    
    // 不加修飾的 init 方法都需要在方法中保證所有非 Optional 得實例變量被賦值初始化
    init(num: Int) { 
        numA = num    
    }
}

class ClassB: ClassA {    
    let numB: Int    
    override init(num: Int) {       
        numB = num + 1  // 在 init 里我們可以對 let 的實例常量進行賦值,這是初始化方法的重要特點。正常情況下 let 聲明的值是不可變的,無法被賦值,這對構建線程安全的 API 十分有用。而 init 只可能被調用一次,所以在 init 里我們可以為不變量進行賦值,而不會引起任何線程安全的問題        
        super.init(num: num)    
    }
}

 

與 designated 初始化方法啊對應的是在 init 前加上 convenience 關鍵字的初始化方法。這類方法只作為補充和提供使用上的方便。所有的 convenience 初始化方法都必須調用同一個類中的 designated 初始化完成設置,另外 convenience 的初始化方法是不能被子類重寫或者是從子類中以 super 的方式被調用的。

class ClassAA {    
    let numA: Int    
    init(num: Int) {        
        numA = num    
    }    
    convenience init(bigNum: Bool) {        
        self.init(num: bigNum ? 10000 : 1) // 所有的 convenience 初始化方法都必須調用同一個類中的 designated 初始化完成設置    
    }
}

class ClassBB: ClassAA {    
    let numB: Int    
    override init(num: Int) {        
        numB = num + 1        
        super.init(num: num)    
    }
}

 

只要在子類中實現重寫了父類 convenience 方法所需要的 init 方法的話,我們在子類中就可以使用父類的 convenience 初始化方法了。比如上面我們即使在 ClassBB 中沒有 bigNum 版本的 convenience init(bigNum: Bool),我們仍然是可以是用這個方法來完成子類初始化的:

let anObj = ClassBB(bigNum: true)
print(anObj.numA, anObj.numB)

輸出:10000和10001

 

總結:初始化方法永遠遵循以下兩個原則

1.初始化路徑必須保證對象完全初始化,這可以通過調用本類型的 designated 初始化方法得到保證;

2.子類的 designated 初始化方法必須調用父類的 designated 方法,以保證父類也完成初始化。

 

  對於某些我們希望子類中一定實現的 designated 初始化方法,我們可以通過添加 required 關鍵字進行限制,強制子類對這個方法重寫實現。這樣做的最大的好處是可以保證依賴於某個 designated 初始化方法的 convenience 一直可以被使用。

下面的代碼中如果希望初始化方法對於子類一定可用,就將 init(num: Int) 聲明為必須。

class ClassAAA {    
    let numA: Int    
    required init(num: Int) {        
        numA = num    
    }    
    required convenience init(bigNum: Bool) {        
        self.init(num: bigNum ? 10000 : 1)    
    } 
}

class ClassBBB: ClassAAA {    
    let numB: Int    
    required init(num: Int) {        
        numB = num + 1        
        super.init(num: num)    
    }
}

let sencondObj = ClassBB(bigNum: true)
print(sencondObj.numA, sencondObj.numB)

輸出:10000和10001

 

對於 convenience 的初始化方法也可以加上 required 以確保子類對其進行實現。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM