這裏是官網連接,畢竟官網更加權威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的形式使結構更加清晰,可複用性更高,下降耦合度。