- 使用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
最后編輯于 :
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
推薦閱讀更多精彩內容
- 協議定義了一個藍圖 規定了用來實現某一特定工作或者功能所必需的方法和屬性類 結構體 枚舉類型都可以遵循協議 并提供...