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 的协议世界中,每一个对象均可能遵照许多协议,而协议自己能够做为一种类型,在使用类型推断时,编译器会把对象推断为对象自己。

  • 好比说上例中,你能够经过指定实例的类型修改上下文。

五、协议继承

  • 协议自己能够继承自另外一个协议,固然不能继承自另外一个类,由于协议是不能有具体方法实现的,因此不能继承自类,协议继承自另外一个协议,无非就是多了一个方法定义。

  • 协议也有继承关系,若是想要遵照这个协议,就必须把它继承的协议也所有实现。

相关文章
相关标签/搜索