協議是爲方法、屬性等定義一套規範,沒有具體的實現,相似於Java中的抽象接口,它只是描述了方法或屬性的骨架,而不是實現。方法和屬性實現還須要經過定義類,函數和枚舉完成。swift
//協議定義經過關鍵字protocol protocol SomeProtocol { //協議定義 } //協議能夠繼承一個或者多個協議 protocol SomeProtocol2: SomeProtocol { //協議定義 } //結構體實現協議 struct SomeStructure: SomeProtocol, SomeProtocol2 { //結構體定義 } //類實現協議和繼承父類,協議通常都寫在父類後面 class SomeSuperclass { //父類定義 } class SomeClass: SomeSuperclass, SomeProtocol, SomeProtocol2 { //子類定義 }
協議不指定是否該屬性應該是一個存儲屬性或者計算屬性,它只指定所需的屬性名稱和讀寫類型。屬性要求老是聲明爲變量屬性,用var
關鍵字作前綴。數組
protocol ClassProtocol { static var present: Bool { get set } //要求該屬性可讀可寫,而且是靜態的 var subject: String { get } //要求該屬性可讀 var stname: String { get set } //要求該屬性可讀可寫 } //定義類來實現協議 class MyClass: ClassProtocol { static var present = false //若是沒有實現協議的屬性要求,會直接報錯 var subject = "Swift Protocols" //該屬性設置爲可讀可寫,也是知足協議要求的 var stname = "Class" func attendance() -> String { return "The \(self.stname) has secured 99% attendance" } func markssecured() -> String { return "\(self.stname) has \(self.subject)" } } //建立對象 var classa = MyClass() print(classa.attendance()) //結果:The Class has secured 99% attendance print(classa.markssecured()) //結果:Class has Swift Protocols
協議能夠要求指定實例方法和類型方法被一致的類型實現。這些方法被寫爲協議定義的一部分,跟普通實例和類型方法徹底同樣,可是沒有大括號或方法體。可變參數是容許的,普通方法也遵循一樣的規則,不過不容許給協議方法參數指定默認值。app
//定義協議,指定方法要求 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) % m) return lastRandom / m } } let generator = LinearCongruentialGenerator() print("隨機數: \(generator.random())") //結果:隨機數: 0.37464991998171 print("另外一個隨機數: \(generator.random())") //結果:另外一個隨機數: 0.729023776863283
有時須要一個方法來修改它屬於的實例。對值類型實例方法(即結構和枚舉),你將mutating
關鍵字放在方法func
關鍵字以前,代表該方法容許修改所屬實例的任何屬性。這個過程描述在實例方法內修改值類型,一般用於結構體和枚舉。dom
protocol Togglable { //協議的Mutating方法要求,容許在該方法內修改值類型 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() //此時lightSwitch變成了OnOffSwitch.On switch(lightSwitch) { case .On: print("開關On") case .Off: print("開關Off") } //打印:開關On
協議SomeProtocol
中不光能夠聲明方法/屬性/下標,還能夠聲明構造器,但在Swift
中,除了某些特殊狀況外,構造器是不被子類繼承的,因此SomeClass
中雖然可以保證定義了協議要求的構造器,但不能保證SomeClass
的子類中也定義了協議要求的構造器。因此咱們須要在實現協議要求的構造器時,使用required
關鍵字確保SomeClass
的子類必須也得實現這個構造器。tcp
protocol TcpProtocol { //初始化構造器要求 init(aprot: Int) } class TcpClass: TcpProtocol { var aprot: Int //實現協議的初始化要求時,必須使用required關鍵字確保子類必須也得實現這個構造器 required init(aprot: Int) { self.aprot = aprot } } var tcp = TcpClass(aprot: 20) print(tcp.aprot)
//定義隨機數生成器協議 protocol RandomNumberGenerator { func random() -> Double } //實現RandomNumberGenerator協議的類 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) % m) return lastRandom / m } } //定義骰子類 class Dice { let sides: Int //表示「骰子」有幾個面 let generator: RandomNumberGenerator //隨機數生成器 //指定構造器,RandomNumberGenerator是一個協議名 init(sides: Int, generator: RandomNumberGenerator) { self.sides = sides self.generator = generator } //搖動「骰子」 func roll() -> Int { return Int(generator.random() * Double(sides)) + 1 } } //建立一個6面骰子 var dice6 = Dice(sides: 6, generator: LinearCongruentialGenerator()) for i in 1...5 { print("搖動骰子:\(dice6.roll())") } /* 搖動骰子:3 搖動骰子:5 搖動骰子:4 搖動骰子:5 搖動骰子:4 */
協議組合對於要求一個類型當即符合多種協議是有用的。ide
protocol Named { var name: String { get } } protocol Aged { var age: Int { get } } //定義結構體實現上面2個協議 struct Person: Named, Aged { var name: String var age: Int } //定義一個函數,接受一個符合Named和Aged協議的類型 func wishHappyBirthday(celebrator: protocol<Named, Aged>) { print("\(celebrator.name)\(celebrator.age)歲生日快樂!") } //建立一個Person結構體,實現了Named和Aged協議 let birthdayPerson = Person(name: "小明", age: 21) wishHappyBirthday(birthdayPerson) //結果:小明21歲生日快樂!
OC
中協議定義的屬性和變量有required
和optional
,Swift
中你能夠爲協議定義optional
要求,這些要求不須要被符合協議的類型實現。函數
Optional
協議要求只有在你的協議被@objc
屬性標記時指定。Objective-C
交互,若是你但願指定optional
要求,你仍然須要使用@objc
標記你的協議。@objc
標記的協議只能經過類調用根據個人理解,Swift
的設計理念是沒有可選的協議實現概念,可是爲了保持與OC
兼容性,不得已支持;因此在Swift
的協議中定義可選實現的前提是該協議被@objc
修飾,關於@objc
:ui
@objc
指示該協議暴露給OC
,便可覺得OC
代碼所用@objc
修飾的協議僅僅能夠被類class
類型遵循@objc protocol CounterDataSource { //協議可選實現的方法要求 @optional func incrementForCount(count: Int) -> Int //協議可選實現的屬性要求 @optional var fixedIncrement: Int { get } } @objc class Counter { var count = 0 var dataSource: CounterDataSource? //數據源屬性,可選類型 func increment() { //判斷是否數據源有,數據源是否有實現可選的方法和屬性 if let amount = dataSource?.incrementForCount?(count) { count += amount } else if let amount = dataSource?.fixedIncrement? { count += amount } } } @objc class ThreeSource: CounterDataSource { let fixedIncrement = 3 } var counter = Counter() counter.dataSource = ThreeSource() //設置數據源 for i in 1...4 { counter.increment() print("\(counter.count) ") //打印:3 6 9 12 }
dataSource
可能爲nil
,所以在dataSource
後邊加上了?
標記來代表只在dataSource
非空時纔去調用incrementForCount
方法。dataSource
存在,可是也沒法保證其是否實現了incrementForCount
方法,所以在incrementForCount
方法後邊也加有?
標記。