swift 學習- 25 -- 協議 02

來源:互聯網
上載者:User

標籤:自己的   基於   自己實現   選擇   參數   type   asa   例子   強制轉換   

// 通過擴充添加協議一致性

// 即便無法修改原始碼, 依然可以通過擴充 令已有類型遵循並符合協議, 擴充可以為已有類型添加屬性, 方法, 下標 以及構造器, 因此可以符合協議中的相應要求

 

// 注意: 通過擴充令已有類型遵循並符合協議時, 該類型的所有勢力也會隨之獲得協議中定義的各項功能

 

protocol TextRepresentbble{

    var textualDescription: String { get }

}

 

// 可以通過擴充, 令已有的類 Dice 遵循並符合 TextRepresentable 協議:

 

// extension Dice: TextOutputStream{

//     var textualDescription: String{

//         return "ddddd"

//     }

// }

 

 

// 通過擴充遵循並符合協議, 和在原始定義中遵循並符合協議的效果完全相同, 協議名稱寫在類型名之後, 以冒號隔開, 然後在擴充的大括弧內實現協議要求的內容

 

 

 

 

 

// 通過擴充遵循協議

// 當一個類型已經符合某個協議中的所有要求, 卻還沒有聲明遵循該協議時, 可以通過空擴充體來遵循該協議:

 

struct Hamster{

    var name: String

    var textualDescription: String {

        return "A hamster named \(name)"

    }

}

 

extension Hamster: TextRepresentbble{}

 

// 從現在起, Hamster 的執行個體可以作為 TextRepresentable 類型使用

 

let simonTheHamster = Hamster.init(name: "Simon")

let somethingTextRepresentable: TextRepresentbble = simonTheHamster

print(somethingTextRepresentable.textualDescription)

 

 

// 注意: 即使滿足了協議的所有要求, 類型也不會自動遵循協議, 必須顯式地遵循協議

 

 

 

 

// 協議類型的集合

// 協議類型可以在數組或字典這樣的集合中使用

 

let things: [TextRepresentbble] = [simonTheHamster]

 

// 如下所示, 可以便利 things 數組, 並列印每個元素的文本資訊

 

for thing in things {

    print(thing.textualDescription)

}

 

// thing 是 TextRepresentbble 類型而不是 Hamster 類型, 即使執行個體在幕後確實是這些類型中的一種, 由於 thing 是 TextRepresentbble 類型, 任何 TextRepresentbble 的執行個體都有一個 textualDescription 屬性, 所以每次迴圈中可以安全地反問 thing.textualDescription

 

 

 

 

 

// 協議的繼承

// 協議能夠繼承 一個 或 多個其他協議, 可以在繼承 的協議的基礎上增加新的要求, 協議的繼承文法與 類的繼承很相似, 多個被繼承的協議之間用 (,) 分割

 

// protocol InheritingProtocol: SomeProtocol, AnotherProtocl{

    // 這裡是協議的定義部分

// }

 

// 如下例所示:

protocol PrettyTextRepresentable: TextRepresentbble{

    var prettyTextualDescription: String { get }

}

 

// 例子中定義了一個新的協議 PrettyTextRepresentable, 它繼承自 TextRepresentable 協議, 任何遵循 PrettyTextRepresentable 洗衣的類型在滿足該協議的要求時, 也必須滿足 TextRepresentbble 協議的要求.

 

//extension SnakesAndLadders: PrettyTextRepresentable {

//    var prettyTextualDescription: String {

//        var output = textualDescription + ":\n"

//        for index in 1...finalSquare {

//            switch board[index] {

//            case let ladder where ladder > 0:

//                output += "▲ "

//            case let snake where snake < 0:

//                output += "▼ "

//            default:

//                output += "○ "

//            }

//        }

//        return output

//    }

//}

 

 

//上述擴充令 SnakesAndLadders 遵循了 PrettyTextRepresentable 協議,並提供了協議要求的 prettyTextualDescription 屬性。每個 PrettyTextRepresentable 類型同時也是 TextRepresentable 類型,所以在 prettyTextualDescription 的實現中,可以訪問 textualDescription 屬性。

 

 

 

 

 

// 類類型專屬協議

// 你可以在協議的繼承列表中, 通過添加 class 關鍵字來限制協議只能被 類類型遵循, 而結構體 或枚舉不能遵循該協議, class 關鍵字必須第一個出現在協議的繼承列表中, 在其他繼承的協議之前:

// protocol SomeClassOnlyProtocol: class, SomeInheritedProtocol {

    // 這裡是類類型專屬協議的定義部分

// }

 

// 在以上例子中,協議 SomeClassOnlyProtocol 只能被類類型遵循, 如果嘗試讓結構體或枚舉 類型遵循該協議,則會導致編譯錯誤

 

// 注意: 當協議定義的要求 需要遵循協議的 類型必須是 引用語義 而非 值語義, 應該採用類類型專屬協議

 

 

 

 

// 協議合成

// 有時候需要同時遵循多個協議, 你可以將多個協議採用 SomeProtocol & AntherProtocol 這樣的格式進行組合, 稱為 協議合成. 你可以羅列任意多個你想要遵循的協議, 以與符號 (&) 分割

 

protocol Named{

    var name: String{ get }

    

}

 

protocol Aged{

    var age: Int { get }

    

}

 

 

struct Person: Named,Aged{

    var name: String

    var age: Int

}

 

func wishHappyBirthday(to celebrator: Named & Aged){

    print("Happy birthday , \(celebrator.name), you‘re \(celebrator.age)")

}

 

let birthdayPerson = Person.init(name: "Malcolm", age: 21)

wishHappyBirthday(to: birthdayPerson)

 

// Named 協議包含 String 類型的 name 屬性, Aged 協議包含 Int 類型的 age 屬性, person 結構體遵循了這兩個協議

 

// wishHappyBirthday(to:) 函數的參數 celebrator 的類型為 Named & Aged, 這意味著它不關心參數的具體類型, 只要參數符合這兩個協議即可

 

// 注意: 協議合成不會產生新的, 永久的協議, 而是將多個協議中要求合成到一個只在局部範圍中有效臨時協議中

 

 

 

 

// 檢查協議的一致性

// 你可以使用 類型轉化 中 描述的 is 和 as 操作符來檢查協議的一致性, 即是否符合某協議,並且可以指定轉換到指定的協議類型, 檢查很轉化到某個協議類型在文法上和類型的檢查和轉換完全相同:

 

// is 用來檢查視力是否符合某個協議, 若是返回 true, 否則返回 false

// as? 返回一個可選值, 當執行個體符合某個協議時, 傳回型別為協議類型的可選值, 否則返回 nil

// as! 將執行個體強制向下轉換到某個協議類型, 如果強制轉換失敗, 會引發執行階段錯誤

 

protocol HasArea{

    var area: Double { get }

    

}

 

class Circle: HasArea{

    let pi = 3.1415927

    var radius: Double

    var area: Double{

        return pi * radius * radius

    }

    init(radius: Double) {

        self.radius = radius

    }

}

 

class Country: HasArea{

    var area: Double

    init(area: Double) {

        self.area = area

    }

}

 

// Circle 類把 area 屬性實現為基於儲存型屬性 radius 的計算型屬性, Country 類則把 area 屬性實現為儲存型屬性, 這兩個類都正確地符合了 HasArea 協議

 

// 下面是一個未遵循 HasArea 協議的類

 

class Animal{

    var legs: Int

    init(legs: Int) {

        self.legs = legs

    }

}

 

// Circle. Country ,Animal 並沒有一個共同的基類, 儘管如此, 他們都是類, 他們的執行個體都可以作為 AnyObject 類型的值, 儲存在同一個數組中:

 

let objects: [AnyObject] = [

    Circle.init(radius: 2.0),

    Country.init(area: 243_610),

    Animal.init(legs: 4)

    

]

 

 

for object in objects {

    if let objectWithArea = object as? HasArea {

        print("Area is \(objectWithArea.area)")

    }else{

        print("Something that doesn‘t have an area")

    }

}

 

// 當迭代出的元素符合 HasArea 協議時, 將 as? 操作符返回的可選值通過可選綁定, 綁定到 objectWithArea 常量上, objectWithAera 是 HasArea 協議類型的執行個體, 因此 area 屬性可以被訪問和列印

 

// objects 數組中的元素的類型並不會因為強轉而丟失類型資訊, 他們仍然是 Circle , Country , Animal 類型, 然而,當他們被賦值給 objectWithArea 常量時, 只被視為 HasArea 類型, 因此只有 area 屬效能被訪問

 

 

 

 

// 可選的協議要求

// 協議可以定義 可選要求. 遵循協議的類型可以選擇是否實現這些要求, 在協議中使用 optional 關鍵字作為首碼 來定義可選要求, 可選要求用在你需要和 OC 打交道的代碼中, 協議和可選要求都必須帶上 @objc 屬性, 標記 @objc 特性的協議只能被繼承自 OC 類的類 或者 @objc 類遵循, 其他類以及結構體和 枚舉不能遵循這種協議

 

// 使用可選要求時(例如, 可選的方法或者屬性) , 他們的類型會自動變成可選的, 比如, 一個類型為 (Int) -> String 的方法會變成 ((Int) -> String)?, 需要注意的是整個函數類型是可選的, 而不是傳回值是可選的

 

// 協議中的可選要求可通過可選鏈式調用來使用, 因為遵循協議的類型可能沒有實現這些可選要求, 類似 someOptionalMethod?(someArgument) 這樣,你可以在可選方法名稱後加上 ? 來調用可選方法。

 

 

@objc protocol CounterDataSource{

   @objc optional func incrementForCount(count: Int) -> Int

   @objc optional var fixedIncrement: Int { get }

}

 

// 注意: 嚴格來講, CounterDataSource 協議中的方法和屬性都是可選的, 因此遵循協議的類可以不實現這些要求, 儘管技術上允許這麼做, 不過做好不要這麼寫

 

class Counter{

    var count = 0

    var dataSource: CounterDataSource?

    func increment() {

        if let amount = dataSource?.incrementForCount?(count: count) {

            count += amount

        }else if let amount = dataSource?.fixedIncrement{

            count += amount

        }

    }

}

 

 

 

 

 

// 協議擴充

// 協議可以通過擴充來為遵循協議的類型提供屬性, 方法以及下標的實現, 你可以基於協議本身來實現這些功能, 而無需在每個遵循協議的類型中都重複同樣的實現, 也無需使用全域函數

 

// 例如. 

//extension SomeProtocol {

//    func randomBool() -> Bool {

//        return random() > 0.5

//    }

//}

 

 

// 通過協議擴充, 所有遵循協議的類型, 都能自動獲得這個擴充所增加的方法實現, 無需任何額外的修改

 

 

 

 

 

 

// 提供預設實現

// 可以通過協議擴充來為協議要求的屬性, 方法以及下標 提供預設的實現, 如果遵循協議的類型為這些要求提供了自己的實現, 那麼這些自訂實現將會替代擴充中的預設實現被使用

 

// 注意: 通過協議擴充為協議要求提供的預設實現和可選的協議要求不同, 雖然在這兩種情況下, 遵循協議的類都無需自己實現這些要求, 但是通過擴充提供的預設實現可以直接調用, 而無需使用可選鏈式調用

 

extension PrettyTextRepresentable{

    var prettyTextualDescription: String {

        return textualDescription

    }

}

 

 

 

 

// 為擴充協議添加限制條件

// 在擴充協議的時候, 可以指定一些限制條件, 只有遵循協議的類型滿足這些限制條件時. 才能獲得協議擴充提供的預設實現, 協議限制條件寫在協議名之後, 使用 whrer 子句來描述, 

 

// 例如,你可以擴充 CollectionType 協議,但是只適用於集合中的元素遵循了 TextRepresentable 協議的情況:

 

// extension CollectionType where Generator.Element: TextRepresentbble{

//     // 擴充協議定義的內容

// }

swift 學習- 25 -- 協議 02

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.