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
    }
    
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容