Swift 協議

前言

  • 協議用於統一方法和屬性的名稱,可是協議沒有實現,在其它語言中一般叫作接口。html

    • 協議也是一種數據類型,就像類、結構體和枚舉那樣的數據結構,能夠把它看成參數。
    • 協議也能夠是一個常量或變量,惟一的區別是協議自己沒有實現,它只有聲明,實現由其它遵照協議的對象來實現。
    • 能夠提早在協議擴展中定義協議的默認實現,不過這些默認實現並不屬於協議自己。
  • 使用協議的好處程序員

    • 一是隻實現了該實現的,子類只知道了該知道的。
    • 其次,協議也能夠做爲數據類型來傳輸,這樣在傳遞數據時,咱們不用關注對象的類型,提升了抽象層次和通用性,也就是可複用性。
  • 協議的使用步驟編程

    • 1)聲明協議,很像其它數據類型的聲明,只不過沒有實現而已。
    • 2)擴展協議(可選步驟),能夠指定擴展的適用對象,在擴展中定義默認的實現。
    • 3)遵照協議,有類、結構體或者枚舉表示遵照這個協議。
    • 4)實現協議,遵照協議的數據類型來實現協議中聲明的屬性和方法,改寫得到的默認實現。

一、聲明協議

  • Swift 語言中協議的聲明使用關鍵字 protocolswift

    protocol 協議: 繼承的協議1, 繼承的協議2 {
    
        var 某個屬性: 類型 {set get}
        func 某個方法(參數列表) -> 返回值類型
        init 構造器(參數列表)
    }
  • 1)在協議中加入的屬性能夠不用實現,也不限制因而計算屬性仍是存儲屬性,可是必需要指出屬性的讀寫權限。數據結構

    • {set get} 表示可讀寫,{get} 表示可讀。
    • 當在實現時爲可讀屬性添加 setter 方法,系統也不會報錯,協議中指定的權限只是最低權限。ide

      // 定義協議
      protocol someProtocol {
      
          var num: Int {get}
      }
      class Show: someProtocol {
      
          var so = 1
      
          // 實現協議中定義的屬性
          var num: Int {
              get {
                  return so
              }
              set {
                  so = newValue + 1
              }
          }
      }
      
      var show1 = Show()
      show1.num = 1
      print(show1.num)            // 2
  • 2)類、結構體和枚舉均可以遵照協議。ui

    • 若是是結構體和枚舉類型遵照的協議方法中有對屬性的改動,那麼按照規定,在協議中聲明這個方法時須要將方法指定爲變異方法
    • 若是是類遵照了協議,那麼協議中的變異方法和普通方法沒有區別。code

      mutating func 變異方法名()
  • 3)能夠在協議的定義中指定某個成員爲類型成員,在成員定義前加上關鍵字 static 便可。htm

    protocol someProtocol {
    
        // 定義類型成員
        static func someTypeNethod()
    }
  • 4)限制協議僅和類一塊兒工做也是可行的,只須要在冒號後面添加一個 class 關鍵字,這樣就表明這個協議只能被類所遵照。對象

    protocol 協議: class, 繼承的協議1, 繼承的協議2 {
    
        var 某個屬性: 類型 {set get}
        func 某個方法(參數列表) -> 返回值類型
        init 構造器(參數列表)
    }

二、遵照協議

  • Swift 中遵照協議的格式和繼承父類同樣,把協議名放到類聲明的尾部,在繼承的後面,以逗號隔開。

    • 一個類只能繼承一個父類,可是能夠遵照多個協議。

      calss 某個類: 父類, 協議1, 協議2, ... {}
  • 協議別名

    • 若是多個協議老是一塊兒出現,則可使用 typealias 關鍵字給多個協議起一個別名,typealias 並不會生成新的協議。

      // Swift 3.0 之前
      typealias 協議組合別名 = protocol<協議1, 協議2, ...>
      // Swift 3.0 之前
      typealias 協議組合別名 = 協議1 & 協議2 ...
      calss 某個類: 父類, 協議組合別名 {}
      
      struct 某個結構體: 協議組合別名 {}

三、實現協議

  • 一旦類遵照了這個協議,就必須實現它裏面的全部成員,否則沒法經過編譯,結構體和枚舉也是如此。

  • 若是類遵照的協議中聲明瞭構造器,那麼遵照協議的類在實現這個構造器的時候必須把構造器聲明爲 required,不然根據構造器的繼承原則,可能致使子類沒有實現該構造器的狀況。

四、協議擴展

  • Swift 2.0 以後蘋果宣稱 Swift 是一門 「面向協議編程」 的語言,這是因爲 Swift 2.0 中引入了對協議擴展的特性。

    • 因爲 Swift 是單類繼承,而且結構體和枚舉還不能被繼承,所以對不少有用信息的傳遞形成了必定的麻煩。
    • 擴展協議的好處是,類、結構體和枚舉均可以遵照不止一個協議。
    • 而且遵照協議不會增長類的狀態。

4.1 定義協議屬性的默認值

  • 能夠提早在協議擴展中定義協議的默認實現,不過這些默認實現並不屬於協議自己。

  • 定義兩個協議 Coder 和 Swifter。

    protocol Coder {
        var haveFun: Bool {get}
        var ownMoney: Bool {get}
    }
    
    protocol Swifter {
        var codingLevel: Int {get}
    }
  • 如今有三個公司的程序員,用三個結構體來表示。

    struct CoderFromA: Coder {
    
        var haveFun: Bool = false
        var ownMoney: Bool = false
    
        var name: String
        init(name: String) {
            self.name = name
        }
    }
    
    struct CoderFromB: Coder, Swifter {
    
        var haveFun: Bool = true
        var ownMoney: Bool = true
    
        var codingLevel: Int = 3
    
        var name: String
        init(name: String) {
            self.name = name
        }
    }
    
    struct CoderFromC: Coder, Swifter {
    
        var haveFun: Bool = true
        var ownMoney: Bool = true
    
        var codingLevel: Int = 5    
    
        var name: String
        init(name: String) {
            self.name = name
        }
    }
    // 使用
    
    let coderA = CoderFromA(name: "A")
    print("\(coderA.name) - \(coderA.haveFun) - \(coderA.ownMoney)")
    // A - false - false
    
    let coderB = CoderFromB(name: "B")
    print("\(coderB.name) - \(coderB.haveFun) - \(coderB.ownMoney) - \(coderB.codingLevel)")
    // B - true - true - 3
    
    let coderC = CoderFromC(name: "C")
    print("\(coderC.name) - \(coderC.haveFun) - \(coderC.ownMoney) - \(coderC.codingLevel)")
    // C - true - true - 5
    • 全部程序員都關心本身是否快樂、是否有錢,因此每一個結構體都遵照協議 Coder
    • A 公司的程序員不是 Swift 程序員,而 B 和 C 公司的程序員都是 Swift 程序員,每一個公司的 Swift 程序員的編程能力等級不一樣。
  • 觀察上面的代碼能夠發現 Swift 程序員都是快樂且富有的,所以結構體 CoderFromBCoderFromC 中會有冗餘的部分,這是因爲不一樣的協議間的因果關係形成的,雖然咱們知道這個事實,可是因爲規則的關係咱們不得不重複的去賦值 haveFunownMoney 屬性。

  • 如今使用 swift 的協議擴展,形式以下。

    // 定義協議
    
    protocol Coder {
        var haveFun: Bool {get}
        var ownMoney: Bool {get}
    }
    
    protocol Swifter {
        var codingLevel: Int {get}
    }
    
    // 定義協議擴展,設置默認值
    
    extension Coder where Self: Swifter {
    
        var haveFun: Bool {
            return true
        }
    
        var ownMoney: Bool {
            return true
        }
    }
    // 定義遵照協議的類型
    
    struct CoderFromA: Coder {
    
        var haveFun: Bool = false
        var ownMoney: Bool = false
    
        var name: String
    
        init(name: String) {
            self.name = name
        }
    }
    
    struct CoderFromB: Coder, Swifter {
    
        //var haveFun: Bool = true
        //var ownMoney: Bool = true
    
        var codingLevel: Int = 3
    
        var name: String
    
        init(name: String) {
            self.name = name
        }
    }
    
    struct CoderFromC: Coder, Swifter {
    
        //var haveFun: Bool = true
        //var ownMoney: Bool = true
    
        var codingLevel: Int = 5
    
        var name: String
    
        init(name: String) {
            self.name = name
        }
    }
    // 使用
    
    let coderA = CoderFromA(name: "A")
    print("\(coderA.name) - \(coderA.haveFun) - \(coderA.ownMoney)")
    // A - false - false
    
    let coderB = CoderFromB(name: "B")
    print("\(coderB.name) - \(coderB.haveFun) - \(coderB.ownMoney) - \(coderB.codingLevel)")
    // B - true - true - 3
    
    let coderC = CoderFromC(name: "C")
    print("\(coderC.name) - \(coderC.haveFun) - \(coderC.ownMoney) - \(coderC.codingLevel)")
    // C - true - true - 5
    • 協議擴展中使用 where 限定 Coder 協議的遵照者在同時遵照 Swifter 協議的時候能夠得到本次擴展中的默認實現。
    • 如今當某個數據結構同時遵照 CoderSwifter 時,協議 Coder 中的屬性 haveFunownMoney 會有默認值。
    • 注意協議擴展中不能定義存儲屬性,因此這裏的 haveFunownMoney 的值以計算屬性 get 方法的形式返回。
    • 此時能夠刪除 CoderFromBCoderFromChaveFunownMoney 的聲明。

4.2 定義協議方法的默認實現

  • 在協議的擴展中,除了給協議中定義的方法賦上默認實現外,還能夠定義新的方法並賦上默認實現。

  • 1)常規的寫法

    // 定義協議
    
    protocol SharedString {
        func methodForOverride()
        func methodWithoutOverride()
    }
    // 定義協議擴展,實現方法
    
    extension SharedString {
    
        func methodForOverride() {
            print("method For Override")
        }
    
        func methodWithoutOverride() {
            methodForOverride()
        }
    }
    // 使用
    
    extension String: SharedString {
    
    }
    
    // String 上下文
    let str1: String = "Hello"
    str1.methodForOverride()         // method For Override
    str1.methodWithoutOverride()     // method For Override
    
    // SharedString 上下文
    let str2: SharedString = "Hello"
    str2.methodForOverride()         // method For Override
    str2.methodWithoutOverride()     // method For Override
  • 2)如今在遵照協議的時候從新定義方法 methodForOverride,修改它的實現。

    // 定義協議
    
    protocol SharedString {
        func methodForOverride()
        func methodWithoutOverride()
    }
    // 定義協議擴展,實現方法
    
    extension SharedString {
    
        func methodForOverride() {
            print("method For Override")
        }
    
        func methodWithoutOverride() {
            methodForOverride()
        }
    }
    // 使用
    
    extension String: SharedString {
    
        func methodForOverride() {
            print(self)
        }
    }
    
    // String 上下文
    let str1: String = "Hello"
    str1.methodForOverride()         // Hello
    str1.methodWithoutOverride()     // Hello
    
    // SharedString 上下文
    let str2: SharedString = "Hello"
    str2.methodForOverride()         // Hello
    str2.methodWithoutOverride()     // Hello
  • 3)如今把方法 methodWithoutOverride 的聲明從 SharedString 協議列表中刪除,將它變成一個從聲明到實現都在協議擴展中的方法。

    // 定義協議
    
    protocol SharedString {
    
        func methodForOverride()
    }
    // 定義協議擴展,實現方法
    
    extension SharedString {
    
        func methodForOverride() {
            print("method For Override")
        }
    
        func methodWithoutOverride() {
            methodForOverride()
        }
    }
    // 使用
    
    extension String: SharedString {
    
        func methodForOverride() {
            print(self)
        }
    }
    
    // String 上下文
    let str1: String = "Hello"
    str1.methodForOverride()         // Hello
    str1.methodWithoutOverride()     // Hello
    
    // SharedString 上下文
    let str2: SharedString = "Hello"
    str2.methodForOverride()         // Hello
    str2.methodWithoutOverride()     // Hello
    • 再次在 String 和 `SharedString 兩種上下文中調用方法,結果仍舊是同樣的,看起來 String 對協議方法 methodForOverride 的修改是絕對的。
  • 4)最後一步,把方法 methodForOverride 從協議列表中列表中刪除,如今 SharedString 的聲明列表是空的了。

    // 定義協議
    
    protocol SharedString {
    
    }
    // 定義協議擴展,實現方法
    
    extension SharedString {
    
        func methodForOverride() {
            print("method For Override")
        }
    
        func methodWithoutOverride() {
            methodForOverride()
        }
    }
    // 使用
    
    extension String: SharedString {
    
        func methodForOverride() {
            print(self)
        }
    }
    
    // String 上下文
    let str1: String = "Hello"
    str1.methodForOverride()         // Hello
    str1.methodWithoutOverride()     // method For Override
    
    print("\n")
    
    // SharedString 上下文
    let str2: SharedString = "Hello"
    str2.methodForOverride()         // method For Override
    str2.methodWithoutOverride()     // method For Override
    • 當兩個方法都定義在協議擴展中,而且上下文爲 String 時,methodForOverride 會調用被重寫的版本,而未被重寫的方法 methodWithoutOverride 會調用協議擴展中默認的版本,而且未被重寫的方法內部調用協議中其它方法時得到的也是沒有被重寫的版本,這就是協議擴展的 「靜態特性」。
    • 當兩個方法都定義在協議擴展中,而且上下文爲 SharedString 時,那麼兩個方法都會得到默認的版本。

4.3 動態方法

  • 動態方法的協議方法定義在協議的聲明中,會徹底被協議遵照者重寫,不管你是否在協議擴展中給予協議方法默認實現,得到的協議方法都是被重寫過的。

4.4 靜態方法

  • 靜態方法的協議方法定義在協議的擴展中,當上下文不爲協議類型時,協議中定義的方法會徹底被協議遵照者重寫;當上下文爲協議類型時,會徹底使用默認實現。

4.5 where 關鍵字

  • where 的做用是限定協議擴展有效的條件,在 where 語句中可使用 Self 關鍵字來表明協議的遵照者,能夠指定遵照者是某個類的子類或者遵照了某個協議。

4.6 上下文

  • 在 Swift 的協議世界中,每一個對象均可能遵照許多協議,而協議自己能夠做爲一種類型,在使用類型推斷時,編譯器會把對象推斷爲對象自己。

  • 好比說上例中,你能夠經過指定實例的類型修改上下文。

五、協議繼承

  • 協議自己能夠繼承自另外一個協議,固然不能繼承自另外一個類,由於協議是不能有具體方法實現的,因此不能繼承自類,協議繼承自另外一個協議,無非就是多了一個方法定義。

  • 協議也有繼承關係,若是想要遵照這個協議,就必須把它繼承的協議也所有實現。

相關文章
相關標籤/搜索