swift中,协议是一种类型。协议可以有属性、方法、构造器,可以作为类型定义一个集合(数组、字典),可以继承,也可以作为类型像普通类型一样使用:
作为函数、方法和构造器的参数类型,或者返回类型;
作为常量、变量和属性的类型;
作为数组、字典和元组的元素类型。
协议语法
protocol SomeProtocol {
// 这里是协议的定义部分
}
struct SomeStructure: FirstProtocol, AnotherProtocol {
// 这里是结构体的定义部分
}
class SomeClass: SomeSuperClass, FirstProtocol, AnotherProtocol {
// 这里是类的定义部分
}
协议作为属性要求
protocol SomeProtocol {
var mustBeSettable: Int { get set }
var doesNotNeedToBeSettable: Int { get }
} //用get、set来表示属性可读可写,用get表示属性可读。没有可写不可读的。
protocol AnotherProtocol {
static var someTypeProperty: Int { get set }
} //static表示类型属性要求
方法要求
protocol SomeProtocol {
static func someTypeMethod()
}//static表示类方法要求,实例方法要求去掉static关键字
对于结构体和枚举的实例方法要求,需要加上mutating关键字
protocol Tooglable {
mutating func toggle()
}
构造器要求
protocol SomeProtocol {
init(someParameter: Int)
}
遵循构造器要求的类,如果没有用final标记不会被继承,则需要加required关键字确保所有子类也必须提供此构造器实现,从而也能符合协议。
protocol SomeProtocol {
init()
}
class SomeSuperClass {
init() {
// 这里是构造器的实现部分
}
}
class SomeSubClass: SomeSuperClass, SomeProtocol {
// 因为遵循协议,需要加上 required
// 因为继承自父类,需要加上 override
required override init() {
// 这里是构造器的实现部分
}
}
通过扩展来添加协议
某类或结构体、或枚举定义的时候没有添加某一协议,后面添加协议用extension来标示,
protocol TextRepresentable {
var textualDescription: String { get }
}
extension Dice: TextRepresentable {
var textualDescription: String {
return "A \(sides)-sided dice"
}
}
为已定义的类Dice添加协议TextRepresentable。
协议的继承
protocol InheritingProtocol: SomeProtocol, AnotherProtocol {
// 这里是协议的定义部分
}
检查协议一致性
与检查普通类型一致性一样,也是用is,as?,as!。
委托(代理)模式
委托(代理)模式是指一个类或结构体将一些功能委托给其它类的实例。swift的委托模式实现较简单:定义协议来封装那些需要被委托的功能,这样就能确保遵循协议的类型能提供这些功能。
protocol DiceGame {
var dice: Dice { get }
func play()
}
protocol DiceGameDelegate {
func gameDidStart(_ game: DiceGame)
func game(_ game: DiceGame, didStartNewTurnWithDiceRoll diceRoll: Int)
func gameDidEnd(_ game: DiceGame)
}
class SnakesAndLadders: DiceGame {
let finalSquare = 25
let dice = Dice(sides: 6, generator: LinearCongruentialGenerator())
var square = 0
var board: [Int]
init() {
board = [Int].init(repeating: 0, count: finalSquare + 1)
//board = [Int](repeatElement(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
}
var delegate: DiceGameDelegate?
func play() {
square = 0
delegate?.gameDidStart(self)
gameLoop: while square != finalSquare {
let diceRoll = dice.roll()
delegate?.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)-sided 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")
}
}
let tracker = DiceGameTracker()
let game = SnakesAndLadders()
game.delegate = tracker
game.play()