这里是官网连接,毕竟官网更加权威html
先来看一下官方的定义java
A protocol defines a blueprint of methods, properties, and other requirements that suit a particular task or piece of functionality. The protocol can then be adopted by a class, structure, or enumeration to provide an actual implementation of those requirements. 设计模式
协议(protocal)定义了用于实现某个任务或功能的一系列方法,属性和其它的种种需求。而后这个协议被类(class)或结构体(struct)或枚举类(enum)实现。api
熟悉java的开发者,在看完协议的定义之后,应该会以为和java中的接口(interface)极为类似。java中接口用于定义类的实现,解耦调用类和被调用类,一个接口容许有多个实现。app
总之,protocal就像是一纸合同,全部遵循(conform)了该合同的对象都必须实现该合同中的必须实现的内容dom
下面简单讲一下协议的使用ide
//声明一份协议 protocol SomeProtocol { //在这里定义协议的具体内容 } //一个对象能够遵循多个协议 struct SomeStructure: FirstProtocol, AnotherProtocol { } //若是类有父类,则父类在冒号后的第一个位置,而后才是协议,彼此用分号隔开 class SomeClass: SomeSuperclass, FirstProtocol, AnotherProtocol { // class definition goes here }
协议中属性的声明oop
必须声明属性的类型ui
属性能够为计算属性或存储属性spa
须要说明属性是读写都可或只读
//声明协议,该协议要求可以知足一个只读属性fullName protocol FullyNamed { var fullName: String { get } } //简单的实现 struct Person: FullyNamed { var fullName: String } let john = Person(fullName: "John Appleseed") // john.fullName 是"John Appleseed" //稍复杂的实现,返回姓+名 class Starship: FullyNamed { var prefix: String? var name: String init(name: String, prefix: String? = nil) { self.name = name self.prefix = prefix } var fullName: String { return (prefix != nil ? prefix! + " " : "") + name } } var ncc1701 = Starship(name: "Enterprise", prefix: "USS") // ncc1701.fullName is "USS Enterprise"
协议中方法的声明
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 } } //若实现对象为enum或struct,则对对象内数据有修改的方法应该标注为为mutating protocol Togglable { mutating func toggle() } enum OnOffSwitch: Togglable { case off, on mutating func toggle() { switch self { case .off: self = .on case .on: self = .off } } }
仍是先看一下官方的定义
Delegation is a design pattern that enables a class or structure to hand off (or delegate) some of its responsibilities to an instance of another type. This design pattern is implemented by defining a protocol that encapsulates the delegated responsibilities, such that a conforming type (known as a delegate) is guaranteed to provide the functionality that has been delegated. Delegation can be used to respond to a particular action, or to retrieve data from an external source without needing to know the underlying type of that source.
委托(delegation)是一种支持类或结构体将一部分职责委托给另外一种类型的实例来完成的设计模式。这种设计模式是经过定义一个封装了委托职责的协议来实现的。而后被委托的实例经过听从该协议来确保完成了委托的任务。委托能够用于回应某一个特定的动做(action),或者从不知其内部实现的外部源来得到数据。
下面咱们举一个具体的例子来讲明委托
最多见的委托应该是在视图(View)和控制器(Controller)之间的,在这里先盗用一张老爷爷的图
.]
也就是说,view将本身的一部分职责委托给controller来完成,例如textfield会将textDidBeginEditing和textDidEndEditing之类的职责交给controller,这样controller能够在textfield开始编辑或者结束编辑的时候进行一些操做,好比高亮被选中的textfield,展开和收起键盘,检验输入的内容格式是否正确。controller还能够对数据进行操做,并将结果返回给view。view根据返回的结果渲染界面。
具体的实现以下:
view声明一个委托协议(即view但愿controller替它完成的工做)
view的api持有一个weak委托协议的属性(如 weak var uiTextFieldDelegate:UITextFieldDelegate)
view用这个协议来完成没法独自完成的功能。
controller声明本身遵循这个协议
controller把本身做为delegate对象(uiTextField.delegate = self)
controller实现这个协议(协议为optional的属性或方法不必定须要实现)
由于委托是经过协议来实现的,因此一个委托能够有多个具体的实现,这样就下降了委托方和被委托方彼此之间的耦合。
这里在贴上官网上的代码例子
协议
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 = 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 } 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") } }
delegate使用于须要回调的方法中。这样,被委托对象在不知道委托对象的状况下完成某些职责。委托对象根据被委托对象返回的信息选择后续如何执行。事实上,delegate在很大程度上相似于closure。只是delegate经过protocal的形式使结构更加清晰,可复用性更高,下降耦合度。