Protocol

作者: 夜雨聲煩_ | 来源:发表于2017-12-29 12:46 被阅读0次
    • 使用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
      }
      

    相关文章

      网友评论

          本文标题:Protocol

          本文链接:https://www.haomeiwen.com/subject/fecigxtx.html