格式
protocol SomeProtocol {
// protocol definition goes here
}
如果類有superclass,則將superclass寫在類后,然后接上protocol砾省。
class SomeClass: SomeSuperclass, FirstProtocol, AnotherProtocol {
// class definition goes here
}
property in protocol
property在protocol中只定義類型和名字,并不規(guī)定是stored property還是computed property。
protocol中的property都是以var定義们拙。
protocol SomeProtocol {
var mustBeSettable: Int { get set }
var doesNotNeedToBeSettable: Int { get }
}
如果在protocol中定義為gettable和settable,那么實(shí)現(xiàn)的時候就不能定義成一個constant stored property或者一個read-only property阁吝。如果protocol中定義的是gettable砚婆,那么就實(shí)現(xiàn)的時候可以根據(jù)自己需要決定是否定義成也settable的property。
type property都需要以static關(guān)鍵字定義突勇。
protocol AnotherProtocol {
static var someTypeProperty: Int { get set }
}
method in protocol
instance method 和 type method都可以在protocol中定義射沟,type method定義的時候需要以static修飾。
// type method
protocol SomeProtocol {
static func someTypeMethod()
}
// instance method
protocol RandomNumberGenerator {
func random() -> Double
}
如果需要在protocol的method中改變instance的值与境,需要用mutating修飾验夯。例如:
protocol Togglable {
mutating func toggle()
}
如果你把一個protocol instance method標(biāo)記為mutating,則在class中實(shí)現(xiàn)的時候就沒必要加mutating關(guān)鍵字了摔刁,但是enumration和structure還是需要加挥转。例如:
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 is now equal to .on
initializer in protocol
定義的格式為:
protocol SomeProtocol {
init(someParameter: Int)
}
實(shí)現(xiàn)這個protocol的時候,需要在init前加required關(guān)鍵字共屈。
class SomeClass: SomeProtocol {
required init(someParameter: Int) {
// initializer implementation goes here
}
}
由于final修飾的class是不可以被繼承的绑谣,所以final修飾的class在實(shí)現(xiàn)init方法的時候不需要加required。
如果子類在復(fù)寫一個父類的init方法的時候拗引,恰巧這個init是從protocol中實(shí)現(xiàn)的借宵,則需要使用required和override兩個關(guān)鍵字修飾。
protocol SomeProtocol {
init()
}
class SomeSuperClass {
init() {
// initializer implementation goes here
}
}
class SomeSubClass: SomeSuperClass, SomeProtocol {
// "required" from SomeProtocol conformance; "override" from SomeSuperClass
required override init() {
// initializer implementation goes here
}
}
protocols as types
由于protocol也是一種類型矾削,所以protocol可以和其他類型一樣用在很多地方壤玫,比如:
可以作為參數(shù)類型或者function豁护、method、initializer的返回值欲间。
可以作為一個常量楚里、變量或者property。
可以作為Array猎贴、dictionary或其他容器類型的內(nèi)容班缎。
例如:
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
}
}
可以給generator賦值給任意實(shí)現(xiàn)了RandomNumberGenerator的instance。
protocol還可以用作代理她渴,這點(diǎn)和oc中差不多达址,就不在多說了。
在class趁耗、enum或structure的extension中實(shí)現(xiàn)protocol
protocol TextRepresentable {
var textualDescription: String { get }
}
extension Dice: TextRepresentable {
var textualDescription: String {
return "A \(sides)-sided dice"
}
}
如果一個class沉唠、enumeration或者structure已經(jīng)實(shí)現(xiàn)了一個protocol的所有功能,只是沒有顯示的實(shí)現(xiàn)這個protocol对粪,這時可以用一個empty extension來使其adopt這個protocol右冻。
struct Hamster {
var name: String
var textualDescription: String {
return "A hamster named \(name)"
}
}
extension Hamster: TextRepresentable {}
protocol type的collection
上面說過protocol也是一種類型而且可以存儲在collection中,所以可以創(chuàng)建protocol類型的collection著拭。
let things: [TextRepresentable] = [game, d12, simonTheHamster]
protocol inheritance
protocol可以被繼承纱扭,而且可以多繼承。
protocol InheritingProtocol: SomeProtocol, AnotherProtocol {
// protocol definition goes here
}
class-only protocols
添加class關(guān)鍵字到protocol繼承列表的最前面儡遮,可以限制protocol只被class實(shí)現(xiàn)乳蛾,而不被enumeration和structure實(shí)現(xiàn)。如下:
protocol SomeClassOnlyProtocol: class, SomeInheritedProtocol {
// class-only protocol definition goes here
}
protocol composition
可以設(shè)定一個type同時遵守多個protocol鄙币,通過&符號將他們連接起來肃叶,例如:
protocol Named {
var name: String { get }
}
protocol Aged {
var age: Int { get }
}
struct Person: Named, Aged {
var name: String
var age: Int
}
func wishHappyBirthday(to celebrator: Named & Aged) {
print("Happy birthday, \(celebrator.name), you're \(celebrator.age)!")
}
let birthdayPerson = Person(name: "Malcolm", age: 21)
wishHappyBirthday(to: birthdayPerson)
// Prints "Happy birthday, Malcolm, you're 21!"
protocol composition并沒有創(chuàng)建一個新的、永久性的protocol十嘿,而只是定義了一個臨時性的protocol把所有的requirement組合到一個protocol中因惭。
checking for protocol conformance
根據(jù)前面的type cast中的介紹,這里同樣有is绩衷、as蹦魔?、as咳燕!來作類型檢測和轉(zhuǎn)換勿决,用法和之前一致,就不在介紹了招盲。
optional protocol requirements
protocol可以定義為optioal低缩,需要在被定義為optional的內(nèi)容前面加關(guān)鍵字optional,估計應(yīng)該是為了與oc兼容。格式如下:
@objc protocol CounterDataSource {
@objc optional func increment(forCount count: Int) -> Int
@objc optional var fixedIncrement: Int { get }
}
摘錄來自: Apple Inc. “The Swift Programming Language (Swift 3)”曹货。 iBooks.
可以看到protocol定義前面和每個optional的method前面都用@objc修飾咆繁。
protocol extension
可以為protocol本身定義extension讳推。格式為:
extension RandomNumberGenerator {
func randomBool() -> Bool {
return random() > 0.5
}
}
通過extension,我們可以為protocol中的computed property和method定義默認(rèn)的實(shí)現(xiàn)么介,如果實(shí)現(xiàn)這個protocol的Type本身提供了自己的實(shí)現(xiàn)娜遵,則會覆蓋默認(rèn)的實(shí)現(xiàn)蜕衡。
extension PrettyTextRepresentable {
var prettyTextualDescription: String {
return textualDescription
}
}
我們還可以給protocol的extension添加條件約束壤短,只有符合條件的conforming type才可以使用extension。例如:
extension Collection where Iterator.Element: TextRepresentable {
var textualDescription: String {
let itemsAsText = self.map { $0.textualDescription }
return "[" + itemsAsText.joined(separator: ", ") + "]"
}
}
使用如下:
let murrayTheHamster = Hamster(name: "Murray")
let morganTheHamster = Hamster(name: "Morgan")
let mauriceTheHamster = Hamster(name: "Maurice")
let hamsters = [murrayTheHamster, morganTheHamster, mauriceTheHamster]
//使用
print(hamsters.textualDescription)
// Prints "[A hamster named Murray, A hamster named Morgan, A hamster named Maurice]
如果一個confirming type對同一個method和property符合多個extensions約束慨仿,則swift會自動從這些extension中挑選一個最合適的選線久脯。