Protocol

  • 使用protocol定义协议
    //Protocol Syntax
    protocol SomeProtocol {
      
    }
    class SomeClass: SuperClass, FirstProtocol, SecondProtocol {
      
    }
    
  • 协议的属性条件:协议只定义属性的名字和类型,不关心是存储属性还是计算属性。同时协议定义可读或可读可写,如果定义成可读可写,那不能够实现为存储属性或者只读属性;相反,如果协议定义为可读,那么如果需要的话,可以实现为可读可写
    protocol SomeProtocol {
      var mustBeSettable: Int { get set }
      var doesNotNeedToBeSettable: Int { get }
    }
    protocol AnotherProtocol {
      static var someTypeProperty: Int { get set }
    }
    
    类似类型属性,协议中的类型属性要固定加上static,不区分类中为class其他为static
  • 协议属性条件的简单使用
    protocol FullyNamed {
      var fullName: String { get }
    }
    struct Person: FullyNamed {
      var fullName: String
    }
    let john = Person.init(fullName: "Jhon Appleseed")
    
  • 协议方法条件的简单使用
    protocol RandomNumberGenerator {
      func random() -> Double
    }
    class LinearCongruentialGenerator: RandomNumberGenerator {
      var lastRandom = 42.0
      let m = 139968.0
      let a = 3877.0
      let c = 29573.0
      func random() -> Double {
          lastRandom = (lastRandom * a + c).truncatingRemainder(dividingBy: m)
          return lastRandom / m
      }
    }
    let generator = LinearCongruentialGenerator.init()
    print("Here's a random number: \(generator.random())")
    
  • 结构体和枚举(值类型),可是使用mutating关键字修改自身的值,对于协议定义的方法同样如此。同时,在结构体和枚举的实现中也需要mutating关键字,但是类不需要
    //Mutating Method Requirements
    protocol Togglable {
      mutating func toggle()
    }
    enum OnOffSwitch: Togglable {
      case off, on
      mutating func toggle() {
          switch self {
          case .off:
              self = .on
          case .on:
              self = .off
          }
      }
    }
    var lightSwitch = OnOffSwitch.off
    lightSwitch.toggle()
    
  • 协议声明构造器方法时,需要required表示其子类也需要实现,但如果是fianal,即不会有子类时则不需要required
    protocol SomeSimpleInitializerProtocol {
      init()
    }
    class SomeSuperClass {
      init() {
          
      }
    }
    class SomeSubClass: SomeSuperClass, SomeSimpleInitializerProtocol {
      //"required" from SomeProtocol conformance; "override" from SomeSuperClass
      required override init() {
          
      }
    }
    
    
  • 协议也是一种类型,所以同样可以作为参数、返回值;作为属性、变量;作为数组、字典内容。同时注意协议作为类型,首字母大写
    //Protocols as Types
    class Dice {
      let sides: Int
      let generator: RandomNumberGenerator
      init(sides: Int, generator: RandomNumberGenerator) {
          self.sides = sides
          self.generator = generator
      }
      func roll() -> Int {
          return Int(generator.random() * Double(sides)) + 1
      }
    }
    //六面骰子,生成法则使用线性同余生成器
    var d6 = Dice.init(sides: 6, generator: LinearCongruentialGenerator())
    for _ in 1...5 {
      print("Random dice roll is \(d6.roll())")
    }
    
    
  • 代理用于使类和结构体实现另一种类型实例的某种功能,通过使用协议定义需要实现的功能,使用代理具体实现功能
    //Delegation
    //协议DiceGame可以被用于所有使用骰子的游戏
    protocol DiceGame {
      var dice: Dice { get }
      func play()
    }
    //协议DiceGameDelegate可以被用于所有使用跟踪骰子过程的类型
    protocol DiceGameDelegate {
      //提供关于DiceGame的三个代理方法,使用该DiceGameDelegate的实例可以直接调用其三个方法,而不需要关心其内部实现。创建遵循该代理的类具体实现其方法
      //类似于OC中,遵守某协议(:delegate)的类实现该方法。而定义某协议的地方调用该方法
      func gameDidStart(_ game: DiceGame)
      func game(_game: DiceGame, didStartNewTurnWithDiceRoll diceRoll: Int)
      func gameDidEnd(_ game: DiceGame)
    }
    
    //使用骰子的游戏蛇与梯子
    class SnakesAndLadders: DiceGame{
      //25个格
      let finalSquare = 25
      //实现DiceGame协议,指定使用6面线性同余生成随机数的骰子
      let dice = Dice.init(sides: 6, generator: LinearCongruentialGenerator.init())
      //初始为0
      var square = 0
      //定义格子数组
      var board = [Int]()
      //初始化不同格子向上或是向下移动
      init() {
          board = Array(repeating: 0, count: finalSquare + 1)
          board[03] = +08; board[06] = +11; board[09] = +09; board[10] = +02
          board[14] = -10; board[19] = -11; board[22] = -02; board[24] = -08
      }
      //定义DiceGameDelegate类型代理
      //此代理非必须,定义为可选类型
      var delegate: DiceGameDelegate?
      //实现DiceGame协议,实现play方法
      func play() {
          square = 0
          //使用可选控制链避免代理为空时调用方法
          delegate?.gameDidStart(self)
          gameLoop: while square != finalSquare {
              let diceRoll = dice.roll()
              delegate?.game(_game: self, didStartNewTurnWithDiceRoll: diceRoll)
              switch square + diceRoll {
              case finalSquare:
                  break gameLoop
              case let newSquare where newSquare > finalSquare:
                  continue gameLoop
              default:
                  square += diceRoll
                  square += board[square]
              }
          }
          delegate?.gameDidEnd(self)
      }
    }
    
    class DiceGameTracker: DiceGameDelegate {
      var numberOfTurns = 0
      func gameDidStart(_ game: DiceGame) {
          numberOfTurns = 0
          if game is SnakesAndLadders {
              print("Started a new game of Snakes and Ladders")
          }
          print("The game is using a \(game.dice.sides)-sides dice")
      }
      func game(_game: DiceGame, didStartNewTurnWithDiceRoll diceRoll: Int) {
          numberOfTurns += 1
          print("Rolled a \(diceRoll)")
      }
      func gameDidEnd(_ game: DiceGame) {
          print("The game lasted for \(numberOfTurns) turns")
      }
    }
    
    //初始化实现DiceGameDelegate的类型实例
    let tracker = DiceGameTracker.init()
    //初始化游戏
    let game = SnakesAndLadders.init()
    //将游戏代理DiceGameDelegate类型指定为实现该代理的类型实例
    game.delegate = tracker
    //执行游戏的开始方法
    game.play()
    
  • 使用扩展加协议为现有类新增属性
    //Adding Protocol Conformance with an Extension
    protocol TextRepresentable {
      var textualDescription: String { get }
    }
    extension Dice: TextRepresentable {
      var textualDescription: String {
          return "A \(sides)-sides dice"
       }
    }
    
    使用扩展直接为类新增属性方法等,使用协议定义属性方法,然后使用拓展遵循此协议,使所有需要此协议的扩展都可以直接实现(使直接使用扩展由一步变为两步),从调理上更加清晰
  • 如果某个类型实际上遵循了某一协议,但是没有在定义该类型时声明,可以使用空的extension体来声明
    //Declaring Protocol Adoption with an Extension
    struct Hamster {
      var name: String
      var textualDescription: String {
          return "A hamster named \(name)"
      }
    }
    extension Hamster: TextRepresentable {}
    let simonTheHamster = Hamster(name: "Simon")
    let somethingTextRepresentable: TextRepresentable = simonTheHamster
    //print(somethingTextRepresentable.textualDescription)
    print(simonTheHamster.textualDescription)
    
    补充声明了Hamster实际上是遵循了TextRepresentable协议的类型
  • 协议作为类型存储于数组中,所有遵循该协议的类
    let things: [TextRepresentable] = [game, d12, simonTheHamster]
    for thing in things {
      //注意这里的thing是TextRepresentable协议类型,可以访问thing.textualDescription,但是不能访问其他的
      print(thing.textualDescription)
    }
    
    这里也就说明了上面为什么要补充说明Hamster类是遵循TextRepresentable协议的类,否则simonTheHamster存入数组中时会报类型不符的错误
  • 协议可以继承,写法类似于类的继承,不同之处在于协议可以多继承
    protocol InheritingProtocol: SomeProtocol, AnotherProtocol {
      // protocol definition goes here
    }
    
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容