swift備忘錄之protocols

格式

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,那么實現(xiàn)的時候就不能定義成一個constant stored property或者一個read-only property。如果protocol中定義的是gettable,那么就實現(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標記為mutating,則在class中實現(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)
}

實現(xiàn)這個protocol的時候,需要在init前加required關(guān)鍵字。

class SomeClass: SomeProtocol {
    required init(someParameter: Int) {
        // initializer implementation goes here
    }
}

由于final修飾的class是不可以被繼承的,所以final修飾的class在實現(xiàn)init方法的時候不需要加required。

如果子類在復(fù)寫一個父類的init方法的時候,恰巧這個init是從protocol中實現(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可以和其他類型一樣用在很多地方,比如:

  1. 可以作為參數(shù)類型或者function、method、initializer的返回值。

  2. 可以作為一個常量、變量或者property。

  3. 可以作為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賦值給任意實現(xiàn)了RandomNumberGenerator的instance。

protocol還可以用作代理,這點和oc中差不多,就不在多說了。

在class、enum或structure的extension中實現(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)實現(xiàn)了一個protocol的所有功能,只是沒有顯示的實現(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實現(xiàn),而不被enumeration和structure實現(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定義默認的實現(xiàn),如果實現(xiàn)這個protocol的Type本身提供了自己的實現(xiàn),則會覆蓋默認的實現(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中挑選一個最合適的選線。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,119評論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,382評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,038評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,853評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 71,616評論 6 408
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,112評論 1 323
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,192評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,355評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,869評論 1 334
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 40,727評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,928評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,467評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,165評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,570評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,813評論 1 282
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,585評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 47,892評論 2 372

推薦閱讀更多精彩內(nèi)容