swift學習筆記4——擴展、協議

以前學習swift時的我的筆記,根據github:the-swift-programming-language-in-chinese學習、總結,將重要的內容提取,加以理解後整理爲學習筆記,方便之後查詢用。詳細能夠參考the-swift-programming-language-in-chinese,或者蘋果官方英文版文檔html

當前版本是swift2.2ios

擴展(Extensions)

擴展 就是爲一個已有的類、結構體、枚舉類型或者協議類型添加新功能。這包括在沒有權限獲取原始源代碼的狀況下擴展類型的能力(即 逆向建模 )。擴展和 Objective-C 中的分類相似。(與 Objective-C 不一樣的是,Swift 的擴展沒有名字。)git

若是你經過擴展爲一個已有類型添加新功能,那麼新功能對該類型的全部已有實例都是可用的,即便它們是在這個擴展定義以前建立的。github

計算型屬性(Computed Properties)

擴展能夠爲已有類型添加計算型實例屬性和計算型類型屬性。不能夠添加存儲性屬性swift

構造器(Initializers)

擴展能夠爲已有類型添加新的構造器。這可讓你擴展其它類型,將你本身的定製類型做爲其構造器參數,或者提供該類型的原始實現中未提供的額外初始化選項。數組

擴展能爲類添加新的便利構造器,可是它們不能爲類添加新的指定構造器或析構器。指定構造器和析構器必須老是由原始的類實現來提供。安全

方法(Methods)

擴展能夠爲已有類型添加新的實例方法和類型方法。app

可變實例方法(Mutating Instance Methods)

經過擴展添加的實例方法也能夠修改該實例自己。結構體和枚舉類型中修改 self 或其屬性的方法必須將該實例方法標註爲 mutating,正如來自原始實現的可變方法同樣。ide

下面的例子爲 Swift 的 Int 類型添加了一個名爲 square 的可變方法,用於計算原始值的平方值:函數

extension Int {
    mutating func square() {
        self = self * self
    }
}

下標(Subscripts)

擴展能夠爲已有類型添加新下標。這個例子爲 Swift 內建類型 Int 添加了一個整型下標。該下標 [n] 返回十進制數字從右向左數的第 n 個數字:

123456789[0] 返回 9
123456789[1] 返回 8

嵌套類型(Nested Types)

擴展能夠爲已有的類、結構體和枚舉添加新的嵌套類型:

協議

Mutating 方法要求

若是你在協議中定義了一個實例方法,該方法會改變採納該協議的類型的實例,那麼在定義協議時須要在方法前加 mutating 關鍵字。這使得結構體和枚舉可以採納此協議並知足此方法要求。

將 mutating 關鍵字做爲方法的前綴,寫在 func 關鍵字以前,表示能夠在該方法中修改它所屬的實例以及實例的任意屬性的值

實現協議中的 mutating 方法時,如果類類型,則不用寫 mutating 關鍵字。而對於結構體和枚舉,則必須寫 mutating 關鍵字。

協議構造器要求

協議能夠要求採納協議的類型實現指定的構造器。你能夠像編寫普通構造器那樣,在協議的定義裏寫下構造器的聲明,但不須要寫花括號和構造器的實體:

protocol SomeProtocol {
    init(someParameter: Int)
}

構造器要求在類中的實現

你能夠在採納協議的類中實現構造器,不管是做爲指定構造器,仍是做爲便利構造器。不管哪一種狀況,你都必須爲構造器實現標上 required 修飾符:

class SomeClass: SomeProtocol {
    required init(someParameter: Int) {
        // 這裏是構造器的實現部分
    }
}

使用 required 修飾符能夠確保全部子類也必須提供此構造器實現,從而也能符合協議。

構造器要求
協議能夠要求採納協議的類型實現指定的構造器。你能夠像編寫普通構造器那樣,在協議的定義裏寫下構造器的聲明,但不須要寫花括號和構造器的實體:

protocol SomeProtocol {
init(someParameter: Int)
}
構造器要求在類中的實現

你能夠在採納協議的類中實現構造器,不管是做爲指定構造器,仍是做爲便利構造器。不管哪一種狀況,你都必須爲構造器實現標上 required 修飾符:

class SomeClass: SomeProtocol {
    required init(someParameter: Int) {
        // 這裏是構造器的實現部分
    }
}

使用 required 修飾符能夠確保全部子類也必須提供此構造器實現,從而也能符合協議。

若是一個子類重寫了父類的指定構造器,而且該構造器知足了某個協議的要求,那麼該構造器的實現須要同時標註 required 和 override 修飾符:

protocol SomeProtocol {
    init()
}

class SomeSuperClass {
    init() {
        // 這裏是構造器的實現部分
    }
}

class SomeSubClass: SomeSuperClass, SomeProtocol {
    // 由於採納協議,須要加上 required
    // 由於繼承自父類,須要加上 override
    required override init() {
        // 這裏是構造器的實現部分
    }
}

若是類已經被標記爲 final,那麼不須要在協議構造器的實現中使用 required 修飾符,由於 final 類不能有子類

協議做爲類型

儘管協議自己並未實現任何功能,可是協議能夠被當作一個成熟的類型來使用。

  • 做爲函數、方法或構造器中的參數類型或返回值類型
  • 做爲常量、變量或屬性的類型
  • 做爲數組、字典或其餘容器中的元素類型

經過擴展采納協議

當一個類型已經符合了某個協議中的全部要求,卻尚未聲明採納該協議時,能夠經過空擴展體的擴展來採納該協議:

struct Hamster {
    var name: String
    var textualDescription: String {
        return "A hamster named \(name)"
    }
}
extension Hamster: TextRepresentable {}

從如今起,Hamster 的實例能夠做爲 TextRepresentable 類型使用:

let simonTheHamster = Hamster(name: "Simon")
let v1: TextRepresentable = simonTheHamster // 能夠賦值
print(v1.textualDescription)

即便知足了協議的全部要求,類型也不會自動採納協議,必須顯式地採納協議。

協議類型的集合

協議類型能夠在數組或者字典這樣的集合中使用,在協議類型提到了這樣的用法。下面的例子建立了一個元素類型爲 TextRepresentable 的數組:

let things: [TextRepresentable] = [game, d12, simonTheHamster]
以下所示,能夠遍歷 things 數組,並打印每一個元素的文本表示:

for thing in things {
    print(thing.textualDescription)
}
// A game of Snakes and Ladders with 25 squares
// A 12-sided dice
// A hamster named Simon

thing 是 TextRepresentable 類型而不是 Dice,DiceGame,Hamster 等類型,即便實例在幕後確實是這些類型中的一種。因爲 thing 是 TextRepresentable 類型,任何 TextRepresentable 的實例都有一個 textualDescription 屬性,因此在每次循環中能夠安全地訪問 thing.textualDescription。

協議的繼承

協議可以繼承一個或多個其餘協議,能夠在繼承的協議的基礎上增長新的要求。協議的繼承語法與類的繼承類似,多個被繼承的協議間用逗號分隔:

protocol InheritingProtocol: SomeProtocol, AnotherProtocol {
    // 這裏是協議的定義部分
}

類類型專屬協議

你能夠在協議的繼承列表中,經過添加 class 關鍵字來限制協議只能被類類型採納,而結構體或枚舉不能採納該協議。class 關鍵字必須第一個出如今協議的繼承列表中,在其餘繼承的協議以前:

protocol SomeClassOnlyProtocol: class, SomeInheritedProtocol {
    // 這裏是類類型專屬協議的定義部分
}

在以上例子中,協議 SomeClassOnlyProtocol 只能被類類型採納。若是嘗試讓結構體或枚舉類型採納該協議,則會致使編譯錯誤。

協議合成

有時候須要同時採納多個協議,你能夠將多個協議採用 protocol<SomeProtocol, AnotherProtocol> 這樣的格式進行組合,稱爲 協議合成(protocol composition)。你能夠在 <> 中羅列任意多個你想要採納的協議,以逗號分隔。

下面的例子中,將 Named 和 Aged 兩個協議按照上述語法組合成一個協議,做爲函數參數的類型:

protocol Named {
    var name: String { get }
}
protocol Aged {
    var age: Int { get }
}
struct Person: Named, Aged {
    var name: String
    var age: Int
}
func wishHappyBirthday(celebrator: protocol<Named, Aged>) {
    print("Happy birthday \(celebrator.name) - you're \(celebrator.age)!")
}

協議合成並不會生成新的、永久的協議類型,而是將多個協議中的要求合成到一個只在局部做用域有效的臨時協議中。

可選的協議要求

協議能夠定義可選要求,採納協議的類型能夠選擇是否實現這些要求。在協議中使用 optional 關鍵字做爲前綴來定義可選要求。使用可選要求時(例如,可選的方法或者屬性),它們的類型會自動變成可選的。好比,一個類型爲 (Int) -> String 的方法會變成 ((Int) -> String)?。須要注意的是整個函數類型是可選的,而不是函數的返回值。

相關文章
相關標籤/搜索