中文字幕在线观看,亚洲а∨天堂久久精品9966,亚洲成a人片在线观看你懂的,亚洲av成人片无码网站,亚洲国产精品无码久久久五月天

Swift初始化的安全方式

2018-07-20    來源:編程學(xué)習(xí)網(wǎng)

容器云強勢上線!快速搭建集群,上萬Linux鏡像隨意使用

我們在深入初始化方法之前,不妨先再想想 Swift 中的初始化想要達(dá)到一種怎樣的目的。

其實就是安全。在 Objective-C 中,init 方法是非常不安全的:沒有人能保證 init 只被調(diào)用一次,也沒有人保證在初始化方法調(diào)用以后實例的各個變量都完成初始化,甚至如果在初始化里使用屬性進(jìn)行設(shè)置的話,還可能會造成各種問題,雖然 Apple 也明確說明了不應(yīng)該在 init 中使用屬性來訪問,但是這并不是編譯器強制的,因此還是會有很多開發(fā)者犯這樣的錯誤。

所以 Swift 有了超級嚴(yán)格的初始化方法。一方面,Swift 強化了 designated 初始化方法的地位。Swift 中不加修飾的 init 方法都需要在方法中保證所有非 Optional 的實例變量被賦值初始化,而在子類中也強制 (顯式或者隱式地) 調(diào)用 super 版本的 designated 初始化,所以無論如何走何種路徑,被初始化的對象總是可以完成完整的初始化的。

class ClassA {
    let numA: Int
    init(num: Int) {
        numA = num
    }
}

class ClassB: ClassA {
    let numB: Int

    override init(num: Int) {
        numB = num + 1
        super.init(num: num)
    }
}

在上面的示例代碼中,注意在 init 里我們可以對 let 的實例常量進(jìn)行賦值,這是初始化方法的重要特點。在 Swift 中 let 聲明的值是不變量,無法被寫入賦值,這對于構(gòu)建線程安全的 API 十分有用。而因為 Swift 的 init 只可能被調(diào)用一次,因此在 init 中我們可以為不變量進(jìn)行賦值,而不會引起任何線程安全的問題。

與 designated 初始化方法對應(yīng)的是在 init 前加上 convenience 關(guān)鍵字的初始化方法。這類方法是 Swift 初始化方法中的 “二等公民”,只作為補充和提供使用上的方便。所有的 convenience 初始化方法都必須調(diào)用同一個類中的 designated 初始化完成設(shè)置,另外 convenience 的初始化方法是不能被子類重寫或者是從子類中以 super 的方式被調(diào)用的。

class ClassA {
    let numA: Int
    init(num: Int) {
        numA = num
    }

    convenience init(bigNum: Bool) {
        self.init(num: bigNum ? 10000 : 1)
    }
}

class ClassB: ClassA {
    let numB: Int

    override init(num: Int) {
        numB = num + 1
        super.init(num: num)
    }
}

只要在子類中實現(xiàn)重寫了父類 convenience 方法所需要的 init 方法的話,我們在子類中就也可以使用父類的 convenience 初始化方法了。比如在上面的代碼中,我們在 ClassB 里實現(xiàn)了 init(num: Int)的重寫。這樣,即使在 ClassB 中沒有 bigNum 版本的 convenience init(bigNum: Bool),我們?nèi)匀贿是可以用這個方法來完成子類初始化:

let anObj = ClassB(bigNum: true)
// anObj.numA = 10000, anObj.numB = 10001

因此進(jìn)行一下總結(jié),可以看到初始化方法永遠(yuǎn)遵循以下兩個原則:

  1. 初始化路徑必須保證對象完全初始化,這可以通過調(diào)用本類型的 designated 初始化方法來得到保證;
  2. 子類的 designated 初始化方法必須調(diào)用父類的 designated 方法,以保證父類也完成初始化。

對于某些我們希望子類中一定實現(xiàn)的 designated 初始化方法,我們可以通過添加 required 關(guān)鍵字進(jìn)行限制,強制子類對這個方法重寫實現(xiàn)。這樣的一個最大的好處是可以保證依賴于某個 designated 初始化方法的 convenience 一直可以被使用。一個現(xiàn)成的例子就是上面的 init(bigNum: Bool):如果我們希望這個初始化方法對于子類一定可用,那么應(yīng)當(dāng)將 init(num: Int) 聲明為必須,這樣我們在子類中調(diào)用 init(bigNum: Bool) 時就始終能夠找到一條完全初始化的路徑了:

class ClassA {
    let numA: Int
    required init(num: Int) {
        numA = num
    }

    convenience init(bigNum: Bool) {
        self.init(num: bigNum ? 10000 : 1)
    }
}

class ClassB: ClassA {
    let numB: Int

    required init(num: Int) {
        numB = num + 1
        super.init(num: num)
    }
}

另外需要說明的是,其實不僅僅是對 designated 初始化方法,對于 convenience 的初始化方法,我們也可以加上 required 以確保子類對其進(jìn)行實現(xiàn)。這在要求子類不直接使用父類中的 convenience 初始化方法時會非常有幫助。

標(biāo)簽: 安全 代碼 開發(fā)者

版權(quán)申明:本站文章部分自網(wǎng)絡(luò),如有侵權(quán),請聯(lián)系:west999com@outlook.com
特別注意:本站所有轉(zhuǎn)載文章言論不代表本站觀點!
本站所提供的圖片等素材,版權(quán)歸原作者所有,如需使用,請與原作者聯(lián)系。

上一篇:iOS開發(fā)的一些奇巧淫技

下一篇:2015年5種可能將要面臨死亡的編程語言