1 協議中能夠定義屬性app
(1)屬性不能夠有默認值iphone
(2)必須設置是「get」仍是「get set」,注意:get與set之間是沒有逗號的函數
(3)即便屬性只有get,沒有set,也不能夠將屬性設置爲let,必須設置爲varui
2 協議中能夠定義方法spa
(1)方法的參數不能夠有默認值設計
protocol Pet { // 定義屬性 var name: String {get set} var birthplace: String {get} // 定義方法 func fed(food: String) func playWith()
mutating func changeName(name: String) }
var pet: Pet
4 定義一個結構體實現該協議code
(1)實現協議中的屬性orm
(I)此時屬性能夠設置默認值對象
(II)協議中name爲可讀可寫的,能夠直接聲明爲var類型就能夠
(III)協議中birthplace爲可讀屬性,能夠直接聲明爲let類型就能夠,固然也能夠聲明爲var類型
(2)實現協議中的方法
(I)能夠爲方法中的參數設置默認值
(II)在結構體中,若是須要改變自身的值,須要在方法前面加mutating關鍵字。在協議的方法中添加mutating關鍵字,若是結構體來遵照協議,須要有 mutating這個關鍵字,若是是類來遵照協議,mutating關鍵字就不須要了。
struct Dog: Pet { var name: String = "Tim" let birthplace: String = "Bei Jing" func fed(food: String = "Bone") { if food == "Bone" { print("I am happy.") } else { print("I need a bone.") } } func playWith() { print("Wong!") } mutating func changeName(name: String) { self.name = name } }
5 將一個Dog類賦值給一個遵照了Pet協議的對象,是沒有問題的。由於協議能夠看成一個類型來看待。
var dog: Dog = Dog() let aPet: Pet = dog
6 若是隻但願協議只被類class遵照,只須要在定義協議的時候在後面加上AnyObject便可。
如下定義的Animate協議只能被類遵照,結構體是不能夠遵照的。
protocol Animate: AnyObject { var name: String {get set} } class Cat: Animate { var name: String = "" }
7 Dog類在實現協議Pet的時候,若是將birthplace聲明爲var是沒有問題的。若是birthplace被看成是Dog的屬性,它是能夠賦值的,但若是birthplace被做爲是Pet的屬性,它是不能夠賦值的。
struct Dog: Pet { // 其他的屬性和方法省略 var birthplace: String = "Beijing" } var dog: Dog = Dog() let aPet: Pet = dog
// 對dog的birthplace屬性賦值是沒有問題的 dog.birthplace = "Shanghai"
// 不能夠對aPet的birthplace屬性賦值。由於在協議Pet中,birthplace是隻讀的
// aPet.birthplace = "Hangzhou"
8 若是協議(Protocol Pet)中定義了構造函數(init),則實現協議的類(Dog)必須實現這個構造函數,而繼承該類(Dog)的子類(Taidi)間接的也實現了該協議,故子類(Taidi)也必須實現這個構造函數。所以須要在類(Dog)的構造函數中填加子類(Taidi)必須實現該方法的標識,即關鍵字required。若是類(Dog)定義爲final類,即其它類不能夠繼承該類,則required關鍵字能夠省略。
protocol Pet { var name: String {get set} var birthplace: String {get} // 定義構造函數 init(name: String) } class Animate { var type = "mamal" } class Dog: Animate, Pet { var name: String = "Tim" var birthplace: String = "Bei Jing" required init(name: String) { self.name = name } } // Dog類也能夠這樣寫 final class Dog: Animate, Pet { var name: String = "Tim" var birthplace: String = "Bei Jing" // 此時required關鍵字就能夠省略 init(name: String) { self.name = name } }
9 類型別名(typealias)和關聯類型(associatedtype)
類型別名(typealias)其實就是給類型從新定義一個名字。
extension Double { var km: Double {return self * 1000.0} var m: Double {return self} var cm: Double {return self / 100} var ft: Double {return self / 3.28084} } let runningDistance: Double = 3.54.km // 咱們能夠給Double設置一個別名Length,則以上代碼就能夠改成下面的代碼 typealias Length = Double extension Double { var km: Length {return self * 1000.0} var m: Length {return self} var cm: Length {return self / 100} var ft: Length {return self / 3.28084} } let runningDistance: Length = 3.54.km
在設計協議(protocol)時,若是有兩個協議,它們的方法和屬性都同樣,只有協議中用到的類型不一樣,咱們就不必定義兩個協議,只須要將這兩個協議合併爲一個就能夠了。這時就能夠在協議中使用關聯類型(associatedtype),相似於類型別名(typealias)。
protocol WeightCalaulate { associatedtype weightType var weight: weightType {get} } // 在類iphone7中,weightType爲Double類型的別名 class iphone7: WeightCalaulate { typealias weightType = Double var weight: weightType { return 0.114 } } // 在類Ship中,weightType爲Int類型的別名 class Ship: WeightCalaulate { typealias weightType = Int var weight: weightType { return 46_328_000 } }
10 協議能夠繼承、能夠擴展
(1)先看下面的代碼:定義了一個協議Record,兩個結構體BaseballRecord、BasketballRecord,這兩個結構體都實現了Record和CustomStringConvertible協議。
protocol Record { var wins: Int {get} var loses: Int {get} func winningPercent() -> Double } struct BaseballRecord: Record, CustomStringConvertible { var wins: Int var loses: Int func winningPercent() -> Double { return Double(wins)/Double(wins + loses) } var description: String { return String(format: "WINS: %d, LOSES: %d", wins, loses) } } struct BasketballRecord: Record, CustomStringConvertible { var wins: Int var loses: Int func winningPercent() -> Double { return Double(wins)/Double(wins + loses) }
var description: String { return String(format: "WINS: %d, LOSES: %d", wins, loses) } }
(2)能夠看到,以上兩個結構體都實現了Record, CustomStringConvertible兩個協議,若是咱們但願只要實現Record協議,就須要實現CustomStringConvertible協議。咱們可讓Record協議繼承自CustomStringConvertible協議,這樣只要實現Record協議,就必須實現CustomStringConvertible協議。代碼以下:
// 協議中定義代碼及結構體中實現的代碼同上,此處省略
protocol Record: CustomStringConvertible { } struct BaseballRecord: Record { } struct BasketballRecord: Record { }
(3)能夠看到,兩個結構體中實現協議的代碼是相同的。若是這一部分代碼能夠寫到協議中,在結構體中就能夠省去重複的代碼。又協議的定義(Protocol Record)中是不能夠實現代碼的,咱們能夠經過擴展協議的方式,在擴展中實現相應的代碼。(在擴展中能夠進行一些默認的實現)
protocol Record: CustomStringConvertible { var wins: Int {get} var loses: Int {get} func winningPercent() -> Double } extension Record { // 定義一個屬性 var gamePlayed: Int { return wins + loses } // 實現Record協議中定義的方法 func winningPercent() -> Double { return Double(wins)/Double(gamePlayed) } // 實現CustomStringConvertible協議 var description: String { return String(format: "WINS: %d, LOSES: %d", wins, loses) }
} struct BaseballRecord: Record { var wins: Int var loses: Int } struct BasketballRecord: Record { var wins: Int var loses: Int } let baseball = BaseballRecord(wins: 3, loses: 2) baseball.winningPercent() print(baseball) // WINS: 3, LOSES: 2
(4)能夠擴展系統中的協議
extension CustomStringConvertible { var descriptionWithDate: String { return NSDate().description + description } } baseball.descriptionWithDate
(5)在協議的擴展中定義的屬性,在實現該協議的結構體中仍能夠重寫該屬性。
struct BaseballRecord: Record { var wins: Int var loses: Int // 重寫了協議擴展中定義的屬性gamePlayed let gamePlayed: Int = 162 }
(6)用where關鍵字對協議作條件限定(where 類型限定)
(I)第一一個結構體FootballRecord,它實現Record協議,而且它新增了一個屬性(平局ties),這樣它的gamePlayed屬性以及winningPercent()方法都須要重寫。代碼以下:
struct FootballRecord: Record { var wins: Int var loses: Int // 定義平局的屬性 var ties: Int var gamePlayed: Int { return wins + loses + ties } func winningPercent() -> Double { return Double(wins)/Double(gamePlayed) } } let football = FootballRecord(wins: 1, loses: 1, ties: 1) football.gamePlayed football.winningPercent()
(II)若是按上面這樣寫,那麼具備「平局屬性」的那些結構體都須要寫上面的那些所有代碼。故咱們能夠再寫一個協議Tieable,而實現了該協議Tieable的結構體的gamePlayed屬性及winningPercent()方法都應該從新定義。能夠對Record協議進行擴展,而且在擴展中增長限制,只有實現了Tieable協議的那些結構體才能夠有這個擴展中的方法和屬性。
// 既實現了Record協議,又實現了Tieable協議的結構體(類),纔可使用這個擴展中的屬性、方法 extension Record where Self: Tieable { var gamePlayed: Int { return wins + loses + ties } func winningPercent() -> Double { return Double(wins)/Double(gamePlayed) } } struct FootballRecord: Record, Tieable { var wins: Int var loses: Int var ties: Int } let football = FootballRecord(wins: 1, loses: 1, ties: 1) football.gamePlayed // 3 football.winningPercent() // 0.3333333333
(7)協議聚合
protocol Prizable { func isPrizable() -> Bool } // 表示Prizable和CustomStringConvertible兩個協議都實現了的結構體才能夠調用該方法 func award(one: Prizable & CustomStringConvertible) { }
(8)泛型約束(在方法定義中能夠用T來表明某個協議,只須要用<T: 協議名>來定義協議就好)
func top<T: Record>(seq: [T]) -> T { }
// 多個協議
func top<T: Record & Prizable>(seq: [T]) -> T {
}
(9)可選協議:如下協議被標識爲@objc屬性,使得它兼容Objective-C代碼。若是協議擁有可選的屬性或方法時,是必須添加@objc的,由於Swift要使用Objective-C的運行時來檢查類所遵照的可選方法是否存在。擁有可選方法的協議只能被類遵照,結構體和枚舉是不能夠遵照該協議的。
@objc protocol Animal { // 注意: 在swift3中optional前面也必須有@objc @objc optional func fly() }