- 使用protocol定义协议
//Protocol Syntax protocol SomeProtocol { } class SomeClass: SuperClass, FirstProtocol, SecondProtocol { }
- 协议的属性条件:协议只定义属性的名字和类型,不关心是存储属性还是计算属性。同时协议定义可读或可读可写,如果定义成可读可写,那不能够实现为存储属性或者只读属性;相反,如果协议定义为可读,那么如果需要的话,可以实现为可读可写
类似类型属性,协议中的类型属性要固定加上static,不区分类中为class其他为staticprotocol SomeProtocol { var mustBeSettable: Int { get set } var doesNotNeedToBeSettable: Int { get } } protocol AnotherProtocol { static var someTypeProperty: Int { get set } }
- 协议属性条件的简单使用
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体来声明
补充声明了Hamster实际上是遵循了TextRepresentable协议的类型//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协议的类,否则simonTheHamster存入数组中时会报类型不符的错误let things: [TextRepresentable] = [game, d12, simonTheHamster] for thing in things { //注意这里的thing是TextRepresentable协议类型,可以访问thing.textualDescription,但是不能访问其他的 print(thing.textualDescription) }
- 协议可以继承,写法类似于类的继承,不同之处在于协议可以多继承
protocol InheritingProtocol: SomeProtocol, AnotherProtocol { // protocol definition goes here }
Protocol
最后编辑于 :
©著作权归作者所有,转载或内容合作请联系作者
- 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
- 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
- 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
推荐阅读更多精彩内容
- 协议定义了一个蓝图 规定了用来实现某一特定工作或者功能所必需的方法和属性类 结构体 枚举类型都可以遵循协议 并提供...