Swift中協(xié)議的簡單介紹

前言

熟悉Objective-C語言的同學(xué)們肯定對協(xié)議都不陌生,在Swift中蘋果將protocol這種語法發(fā)揚的更加深入和徹底。Swift中的protocol不僅能定義方法還能定義屬性,配合extension擴展的使用還能提供一些方法的默認實現(xiàn),而且不僅類可以遵循協(xié)議,現(xiàn)在的枚舉和結(jié)構(gòu)體也能遵循協(xié)議了?;诖吮疚膹?* 1、協(xié)議中定義屬性和方法,2、協(xié)議的繼承、聚合、關(guān)聯(lián)類型,3、協(xié)議的擴展,4、Swift標準庫中常見的協(xié)議,5、為什么要使用協(xié)議** 5個方面結(jié)合自身的學(xué)習(xí)經(jīng)驗簡單介紹一下這種“加強型protocol的使用,入門級、屬于學(xué)習(xí)總結(jié),希望能給正在學(xué)習(xí)Swift的小伙伴們一點啟發(fā)。

協(xié)議中定義屬性和方法

  • 協(xié)議的定義
    官方文檔對協(xié)議的定義是這樣的:

協(xié)議為方法、屬性、以及其他特定的任務(wù)需求或功能定義藍圖。協(xié)議可被類、結(jié)構(gòu)體、或枚舉類型采納以提供所需功能的具體實現(xiàn)。滿足了協(xié)議中需求的任意類型都叫做遵循了該協(xié)議。

Swift中定義一個協(xié)議和定義枚舉、結(jié)構(gòu)體或者類的格式類似,使用protocol關(guān)鍵字:

//定義一個名字為學(xué)生協(xié)議
protocol Student {
}

這里Student是使用**protocol **關(guān)鍵字聲明的一個協(xié)議,和枚舉、結(jié)構(gòu)體、類命名原則相似,Student首字母大寫表示在以后的使用中很可能會將Student看作是一個類型使用。

  • 協(xié)議中定義屬性
    協(xié)議中定義屬性表示遵循該協(xié)議的類型具備了某種屬性,具體來說只能使用var關(guān)鍵字聲明并且必須明確規(guī)定該屬性是可讀的get、還是可讀可寫的get set,另外還可以通過關(guān)鍵字static聲明一個類型屬性。示例如下:
protocol Student {
    //定義一個可讀可寫的 name 屬性
    var name: String { get set }
    //定義一個可讀的 birthPlace 屬性
    var birthPlace: String { get }
    //定義一個類屬性 record
    static var qualification: String {get}
}

和定義方法一樣,我們只需要確定該屬性具體是什么類型并且添加對應(yīng)的關(guān)鍵字,不需要具體的實現(xiàn),更不能為他們賦上初始值(類似于計算屬性)。定義好屬性之后,我們就可以利用屬性來做點事情了。

struct Puple: Student {
    static var qualification: String = "小學(xué)"
    var name: String
    var birthPlace: String = "北京"
}
var p1 = Puple(name: "小明", birthPlace: "上海")

定義一個Puple結(jié)構(gòu)體遵循Student協(xié)議,該結(jié)構(gòu)體中必須存在協(xié)議要求聲明的三個屬性matrikelnummer、namebirthPlace,static修飾的類型屬性必須被有初始值或者存在get、set方法。對于普通的實例屬性協(xié)議并不關(guān)心是計算型屬性還是存儲型屬性。實例中的屬性同樣可以被修改:

var p1 = Puple(name: "小明", birthPlace: "上海")
Puple.qualification = "中學(xué)"

看到這里有的同學(xué)可能有些疑問,birthPlace、qualification明明只有get方法為什么卻可以修改賦值呢?其實協(xié)議中的“只讀”屬性修飾的是協(xié)議這種“類型”的實例,例如下面的例子:

var s1: Student = p1
s1.birthPlace = "廣州"

雖然我們并不能像創(chuàng)建類的實例那樣直接創(chuàng)建協(xié)議的實例,但是我們可以通過“賦值”得到一個協(xié)議的實例。將p1的值賦值給Student類型的變量s1,修改s1birthPlace屬性時編譯器就會報錯:birthPlace是一個只讀的屬性,不能被修改。如果Puple中還存在Student沒有的屬性,那么在賦值過程中s1將不會存在這樣的屬性,盡管這樣做的意義并不大,但是我們從中知道了協(xié)議中getset的具體含義。

  • 協(xié)議中定義方法
    和Objective-C類似,Swift中的協(xié)議可以定義類型方法或者實例方法,方法的參數(shù)不能有默認值(Swift認為默認值也是一種變相的實現(xiàn)),在遵守該協(xié)議的類型中具體實現(xiàn)方法的細節(jié),通過類或?qū)嵗{(diào)用:
protocol Student {
    //類方法
    static func study()
    //實例方法
    func changeName()
}
struct CollageStudent: Student {
    //類方法實現(xiàn)
    static func study() {
    }
    //實例方法實現(xiàn)
    func changeName() {
    }
}
//方法的調(diào)用
CollageStudent.study()
var c1 = CollageStudent()
c1.changeName()

注意:當我們在結(jié)構(gòu)體中的方法修改到屬性的時候需要在方法前面加上關(guān)鍵字mutating表示該屬性能夠被修改(如果是類不需要添加mutating 關(guān)鍵字),這樣的方法叫做:異變方法,和 “在實例方法中修改值類型” 的處理是一樣的。

protocol Student {
    mutating func changeName()
}
struct CollageStudent: Student {
    mutating func changeName() {
        self.name = "小明"
    }
}
var c1 = CollageStudent()
c1.changeName()
  • 協(xié)議中的初始化器
    我們可以在協(xié)議中定義遵循協(xié)議的類型需要實現(xiàn)的指定初始化器(構(gòu)造函數(shù))或者便捷初始化器。
protocol Pet {
    init(name: String)
}
class Cat: Pet {
    var name: String = "Cat"
    required init(name: String) {
        self.name = name
    }
}

Cat由于遵循了Pet協(xié)議,應(yīng)該用required關(guān)鍵字修飾初始化器的具體實現(xiàn)。
如果一個類既繼承了某個類,而且遵循了一個或多個協(xié)議,我們應(yīng)該將父類放在最前面,然后依次用逗號排列。

class SomeClass: OneProtocol, TwoProtocol {
}

這是因為Swift中類的繼承是單一的,但是類可以遵守多個協(xié)議,因此為了突出其單一父類的特殊性,我們應(yīng)該將繼承的父類放在最前面,將遵守的協(xié)議依次放在后面。

  • 多個協(xié)議重名方法調(diào)用沖突
    由于在Swift中并沒有規(guī)定不同的協(xié)議內(nèi)方法不能重名(這樣的規(guī)定也是不合理的)。因此我們在自定義多個協(xié)議中方法重名的情況是可能出現(xiàn)的,比如存在TextOne、TextTwo兩個協(xié)議,定義如下:
protocol TextOne {
    func text() -> Int
}
protocol TextTwo {  
    func text() -> String
}

這兩個協(xié)議中的text()方法名相同返回值不同,如果存在一個類型Person同時遵守了TextOneTextTwo,在Person實例調(diào)用方法的時候就會出現(xiàn)歧義。

struct Person: TextOne, TextTwo {
    func text() -> Int {
        return 10
    }
    func text() -> String { 
        return "hello"
    }
}
let p1 = Person()
//嘗試調(diào)用返回值為Int的方法
let num = p1.text()
//嘗試調(diào)用返回值為String的方法
let string = p1.text()

上面的調(diào)用肯定是無法通過的,因為編譯器無法知道同名text()方法到底是哪個協(xié)議中的方法,那么出現(xiàn)這種情況的根本原因在于調(diào)用哪個協(xié)議的text()不確定,因此我們需要指定調(diào)用特定協(xié)議的text()方法,改進后的代碼如下:

//嘗試調(diào)用返回值為Int的方法
let num = (p1 as TextOne).text()
//嘗試調(diào)用返回值為String的方法
let string = (p1 as TextTwo).text()

也可以理解為在進行調(diào)用前將p1常量進行類型轉(zhuǎn)換。

協(xié)議的繼承、聚合、關(guān)聯(lián)類型

  • 協(xié)議的繼承
    官方文檔說明:

協(xié)議可以繼承一個或者多個其他協(xié)議并且可以在它繼承的基礎(chǔ)之上添加更多要求。協(xié)議繼承的語法與類繼承的語法相似,選擇列出多個繼承的協(xié)議,使用逗號分隔。

protocol OneProtocol {  
}
protocol TwoProtocol {
}
//定義一個繼承子OneProtocol 和 TwoProtocol協(xié)議的新的協(xié)議: ThreeProtocol
protocol ThreeProtocol: OneProtocol, TwoProtocol {
}

如上所示,任何遵守了ThreeProtocol協(xié)議的類型都應(yīng)該同時實現(xiàn)OneProtocolTwoProtocol的要求必須實現(xiàn)的方法或?qū)傩浴?/p>

  • 協(xié)議的聚合
    日常開發(fā)中要求一個類型同時遵守多個協(xié)議是很常見的,除了使用協(xié)議的繼承外我們還可以使用形如OneProtocol & TwoProtocol的形式實現(xiàn)協(xié)議聚合(組合)復(fù)合多個協(xié)議到一個要求里。例如:
//協(xié)議聚合成臨時的類型
typealias Three = TwoProtocol & OneProtocol
//協(xié)議聚合成為參數(shù)的類型
func text(paramter: OneProtocol & TwoProtocol) {
}

一個很常見的例子:定義text函數(shù)的參數(shù)類型使用了協(xié)議的聚合,在這里我們并不關(guān)心paramter是什么類型的參數(shù),只要它遵循這兩個要求的協(xié)議即可。

  • 繼承和聚合在使用上的區(qū)別
    善于思考的同學(xué)可以發(fā)現(xiàn),要實現(xiàn)上面的 "paramter參數(shù)的類型是遵守OneProtocol 和 TwoProtoco" 的效果,完全可以使用協(xié)議的繼承,新定義一個協(xié)議ThreeProtocol繼承自OneProtocolTwoProtocol,然后指定paramter參數(shù)的類型是ThreeProtocol類型。那么這兩種方法有何區(qū)別呢?
    首先協(xié)議的繼承是定義了一個全新的協(xié)議,我們是希望它能夠“大展拳腳”得到普遍使用。而協(xié)議的聚合不一樣,它并沒有定義新的固定協(xié)議類型,相反,它只是定義一個臨時的擁有所有聚合中協(xié)議要求組成的局部協(xié)議,很可能是“一次性需求”,使用協(xié)議的聚合保持了代碼的簡潔性、易讀性,同時去除了定義不必要的新類型的繁瑣,并且定義和使用的地方如此接近,見明知意,也被稱為匿名協(xié)議聚合。但是使用了匿名協(xié)議聚合能夠表達的信息就少了一些,所以需要開發(fā)者斟酌使用。

  • 協(xié)議的檢查
    如何檢查某個類型是否遵循了特定的協(xié)議?:使用關(guān)鍵字 is,同時該運算符會返回一個Bool值用于判斷條件是否成立。

struct Person: OneProtocol {
}
let p1 = Person()
if (p1 is OneProtocol){ //可以理解為:p1 是一個遵守了OneProtocol協(xié)議類型的實例
    print("yes")
}

如何讓定義的協(xié)議只能被類遵守?:使用關(guān)鍵字class,該關(guān)鍵字修飾之后表示協(xié)議只能被類遵守,如果有枚舉或結(jié)構(gòu)體嘗試遵守會報錯。

//只能被類遵守的協(xié)議
protocol FourProtocol: class ,ThreeProtocol {
}
//此處報錯
struct Person: FourProtocol {
}
class Perple: FourProtocol {
}
  • 關(guān)聯(lián)類型
    協(xié)議的關(guān)聯(lián)類型指的是根據(jù)使用場景的變化,如果協(xié)議中某些屬性存在“邏輯相同的而類型不同”的情況,可以使用關(guān)鍵字associatedtype來為這些屬性的類型聲明“關(guān)聯(lián)類型”。
protocol WeightCalculable {
    //為weight 屬性定義的類型別名
    associatedtype WeightType
    var weight: WeightType { get }
}

WeightCalculable是一個“可稱重”協(xié)議,weight屬性返回遵守該協(xié)議具體類型的實例的重量。這里我們使用associatedtype為該屬性的類型定義了一個別名WeightType,換言之在WeightCalculable中并不關(guān)心weight的類型是Int 還是Double或者是其他類型,他只是簡單的告訴我們返回的類型是WeightType,至于WeightType到底是什么類型由遵守該協(xié)議的類中自己去定義。那么這樣做的好處是什么呢?

//定義手機結(jié)構(gòu)體
struct MobilePhone: WeightCalculable {
    typealias WeightType = Double
    var weight: WeightType
}
let iPhone7 = MobilePhone(weight: 0.138)
//定義汽車結(jié)構(gòu)體
struct Car: WeightCalculable {
    typealias WeightType = Int
    var weight: WeightType
}
let truck = Car(weight: 3000_000)

如上所示:MobilePhone、Car類型都遵守了WeightCalculable協(xié)議,都能被稱重,但是手機由于結(jié)構(gòu)精密、體型小巧,小數(shù)點后面的數(shù)字對于稱重來說是必不可少的,所以使用了Double類型,返回0.138千克138克,但是對于汽車這樣的龐然大物在稱重時如果還計較小數(shù)點后面的數(shù)字就顯得沒有意義了,所以使用Int類型,表示3000千克也就是3噸
從上面的例子可以很好的看出由于MobilePhone、Car稱重時邏輯是一樣的,但是對于weight屬性的返回值要求不一樣,如果僅僅因為返回值類型的不同定義兩個類似的協(xié)議一個是Int類型另外一個是Double類型,這樣做顯然是重復(fù)的、不合適的。所以associatedtype在這種情況下就發(fā)揮出作用了,他讓開發(fā)者在遵守協(xié)議時根據(jù)需求去定義返回值的類型,而不是在協(xié)議中寫死。唯一要注意的是:一定要在遵守該協(xié)議的類型中使用typealias規(guī)定具體的類型。不然編譯器就報錯了。

協(xié)議的擴展

協(xié)議的擴展是協(xié)議中很重要的一部分內(nèi)容,主要體現(xiàn)在以下兩個方面:

  • 擴展協(xié)議的屬性和方法
    我們通過一個常見的例子說明一下:
protocol Score {
    var math: Int { get set}
    var english: Int {get set}
    func mathPercent() -> Double
}

首先定義一個Score協(xié)議,里面有兩個Int類型的屬性mathenglish和一個計算數(shù)學(xué)所占分數(shù)的比例的方法mathPercent。

struct Puple: Score {
    var math: Int
    var english: Int
    func mathPercent() -> Double {
        return Double(math) / Double(math + english)
    }
}

定義Puple遵守該協(xié)議,實現(xiàn)了必要的屬性和方法。

let p1 = Puple(math: 90, english: 80)
s1.mathPercent()

通過上面的代碼可以計算出s1中數(shù)學(xué)所占的比例,但是設(shè)想一下如果還有很多個類似Puple結(jié)構(gòu)體的類型都需要遵守該協(xié)議,都需要默認實現(xiàn)mathPercent 方法計算出自己的數(shù)學(xué)分數(shù)所占的比例,還是按照上面的寫法代碼量就很大而且很冗雜了。問題的關(guān)鍵在于:任何遵守Score協(xié)議類型的mathPercent計算邏輯是不變的,而且需要默認實現(xiàn)。那么我們?nèi)绾屋p松的實現(xiàn)這樣的效果呢,答案是:為Score添加方法的擴展。

extension Score {
    func mathPercent() -> Double {
        return Double(math) / Double(math + english)
    }
}

mathPercent的具體實現(xiàn)寫在協(xié)議的擴展里面,就能為所有的遵守Score的類型提供mathPercent默認的實現(xiàn)。

struct CollageStudent: Score {
    var math: Int
    var english: Int
}
let c1 = CollageStudent(math: 80, english: 80)
c1.mathPercent()

如此就能起到“不實現(xiàn)mathPercent方法也能計算出數(shù)學(xué)所占分數(shù)的比例”的效果了。此語法在Swift中有一個專業(yè)術(shù)語叫做:default implementation 即默認實現(xiàn)。包括計算屬性和方法的默認實現(xiàn),但是不支持存儲屬性,如果遵循類型給這個協(xié)議的要求提供了它自己的實現(xiàn),那么它就會替代擴展中提供的默認實現(xiàn)。
通過這樣的語法,我們不僅能為自定義的協(xié)議提供擴展,還能為系統(tǒng)提供的協(xié)議添加擴展,例如,為CustomStringConvertible添加一個計算屬性默認實現(xiàn)的擴展:

extension CustomStringConvertible {
    var customDescription: String {
        return "YQ" + description
    }
}
  • 為存在的類型添加協(xié)議遵守
    官方文檔說明:

擴展一個已經(jīng)存在的類型來采納和遵循一個新的協(xié)議,無需訪問現(xiàn)有類型的源代碼。擴展可以添加新的屬性、方法和下標到已經(jīng)存在的類型,并且因此允許你添加協(xié)議需要的任何需要。

簡單的來說我們可以對存在的類型(尤其是系統(tǒng)的類型)添加協(xié)議遵守。盡管這更像是對“類型的擴展”,但是官方文檔將這部分放在了協(xié)議的擴展中。

extension Double : CustomStringConvertible {
    /// A textual representation of the value.
    public var description: String { get }
}

上面的代碼就是Swift標準庫中對于Double類型添加的一個協(xié)議遵守。除了添加系統(tǒng)協(xié)議的遵守,我們還可以添加自定義的協(xié)議的遵守,其方法都是一樣的,這里就不太贅述了。

  • 總結(jié)
    通過協(xié)議的擴展提供協(xié)議中某些屬性和方法的默認實現(xiàn),將公共的代碼和屬性統(tǒng)一起來極大的增加了代碼的復(fù)用,同時也增加了協(xié)議的靈活性和使用范圍,這樣的協(xié)議不僅僅是一系列接口的規(guī)范,還能提供相應(yīng)的邏輯,是面向協(xié)議編程的基礎(chǔ)。

Swift標準庫中常見的協(xié)議

學(xué)習(xí)完協(xié)議的基礎(chǔ)語法,我們大致熟悉一下Swift標準庫中提供的協(xié)議。


55個標準庫協(xié)議

Swift標準庫為我們提供了55種協(xié)議,他們的命名很有特點,基本是以"Type"、“able”、“Convertible” 結(jié)尾,分別表示該協(xié)議“可以被當做XX類型”、“具備某種能力或特性”、“能夠進行改變或變換”。因此在自定義協(xié)議時應(yīng)該盡可能遵守蘋果的命名規(guī)則,便于開發(fā)人員之間的高效合作。下面介紹一下常見的幾種協(xié)議:

  • Equatable
    Equatable是和比較相關(guān)的協(xié)議,遵守該協(xié)議表示實例能夠用于相等的比較,需要重載==運算符。
struct Student: Equatable {
    var math: Int
    var english: Int
}
//重載 == 運算符
func == (s1: Student, s2: Student) -> Bool {
    return s1.math == s2.math && s1.english == s2.english
}

Student遵守Equatable并且重載了==運算符后就能直接比較兩個學(xué)生的成績是否相等了。

let s1 = Student(math: 80, english: 60)
let s2 = Student(math: 70, english: 90)
s1 == s2 //false

值得注意的是,由于重載==運算符是遵守Equatable協(xié)議后要求我們實現(xiàn)的,因此重載方法應(yīng)該緊跟在遵守該協(xié)議的類型定義后,中間不能有其他的代碼,否則就報錯了。

  • Comparable
    Comparable是和比較相關(guān)的第二個協(xié)議,遵守該協(xié)議表示實例能夠進行比較,需要重載<運算符。
struct Student: Comparable{
    var math: Int
    var english: Int
}
//重載 < 運算符
func < (s1: Student, s2: Student) -> Bool {
    return (s1.math + s1.english) < (s2.math + s2.english)
}
let s1 = Student(math: 80, english: 60)
let s2 = Student(math: 70, english: 90)
s1 < s2 //true
  • CustomStringConvertible
    CustomStringConvertible提供了一種用文本表示一個對象或者結(jié)構(gòu)的方式,可以在任何遵守該協(xié)議的類型中自定義表示結(jié)構(gòu)的文本,需要覆蓋description屬性。
struct Student: CustomStringConvertible{
    var math: Int
    var english: Int
    var description: String {
        return "Your math:" + String(math) + ", english:" + String(english)
    }
}
let s1 = Student(math: 80, english: 60)
print(s1) // Your math:80, english:60
  • ExpressibleByArrayLiteral
    ExpressibleByArrayLiteral提供了使用數(shù)組文本初始化的類型的能力,具體來說使用逗號分隔的值、實例、字面值列表,方括號以創(chuàng)建數(shù)組文本。遵守該協(xié)議需要實現(xiàn)init(arrayLiteral elements: Person.Element...)方法。
struct Person: ExpressibleByArrayLiteral {
    var name: String = ""
    var job: String = ""
    typealias Element = String
    init(arrayLiteral elements: Person.Element...) {  
        if elements.count == 2 {
            name = elements[0]
            job = elements[1]
        }
    }
}
let p1: Person = ["jack", "teacher"]
print(p1.name) //jack
print(p1.job) //teacher

上面的代碼用到了之前關(guān)聯(lián)類型,通過遵守ExpressibleByArrayLiteral,現(xiàn)在的Person就可以使用數(shù)組直接創(chuàng)建實例了。

類似的協(xié)議還有:
ExpressibleByDictionaryLiteral、ExpressibleByStringLiteral、ExpressibleByBooleanLiteral 、ExpressibleByIntegerLiteral等等,相信大家通過名稱就能大概猜出具體作用,由于篇幅有限這里就不再贅述了。

為什么要使用協(xié)議

  • 協(xié)議可以作為類型使用
    協(xié)議作為一種類型是蘋果在Swift中提出的,并且在官方文檔中還為我們具體指出了可以將協(xié)議當做類型使用的場景:

1,在函數(shù)、方法或者初始化器里作為形式參數(shù)類型或者返回類型;

2,作為常量、變量或者屬性的類型;
3,作為數(shù)組、字典或者其他存儲器的元素的類型。

  • 協(xié)議可以解決面向?qū)ο笾幸恍┘值膯栴}

    寵物類圖

    如圖所示的類結(jié)構(gòu)圖中麻雀在寵物類圖中的位置顯得比較尷尬,之所以尷尬是因為麻雀作為一種鳥類,應(yīng)該繼承,但是如果繼承了,就相當于默認了麻雀是一種寵物,這顯然是不和邏輯的。解決此問題的一般方法如下:
    寵物類圖

    乍一看好像解決了這樣的問題,但是仔細想由于Swift只支持單繼承,麻雀沒有繼承類就無法體現(xiàn)麻雀作為一種鳥擁有的特性和方法(比如飛翔),如果此時出現(xiàn)一個新的飛機類,雖然飛機寵物之間沒有任何聯(lián)系,但是飛機是由很多共同特性的(比如飛翔),這樣的特性該如何體現(xiàn)呢?答案還是新建一個類成為動物飛機的父類。面向?qū)ο缶褪沁@樣一層一層的向上新建父類最終得到一個“超級父類”在OC和Swift中是NSObject,盡管問題得到了解決,但是麻雀、飛機之間的共性并沒有得到很好的體現(xiàn)。而協(xié)議的出現(xiàn)正是為了解決這類問題。

    寵物類圖

    事實上寵物類圖中包括動物、飛機等類之間的關(guān)系就應(yīng)該是如上圖所示的簡單繼承關(guān)系。使用協(xié)議將“寵物”、“飛翔”等關(guān)系看作是一種特性,或者是從另一個維度描述這種類別,更重要的是使用協(xié)議并不會打破原有類別之間繼承的父子關(guān)系。和飛翔相關(guān)的代碼統(tǒng)一放在Flyable中,需要“飛翔”這種能力遵守該協(xié)議;和寵物相關(guān)的代碼統(tǒng)一放在PetType中,需要成為寵物遵守該協(xié)議。這些協(xié)議靈活多變結(jié)合原有的面向?qū)ο箢愔g固有的繼承關(guān)系,完美的描述了這個世界。這幅包含了協(xié)議的寵物類圖是本人在學(xué)習(xí)中印象最深刻的,分享出來與大家共勉。
    Swift中的協(xié)議更多的時候是在描述某種屬性,是否應(yīng)該將“寵物”設(shè)計成一個類或者是一個協(xié)議,應(yīng)該根據(jù)當前項目的需求。如果你的世界沒有麻雀、飛機,那么將“寵物”設(shè)計成一個類也是未嘗不可甚至是非常合理的,這點需要我們仔細思考。

  • 面向協(xié)議編程范式
    學(xué)習(xí)使用協(xié)議就不得不提到通過協(xié)議語法延伸出來的 “面向協(xié)議編程范式”,蘋果提出Swift是一門支持面向協(xié)議編程的語言,甚至提倡我們通過協(xié)議、結(jié)構(gòu)體代替部分類的使用,可見協(xié)議這種語法以及面向協(xié)議編程思想在Swift中是多么的重要。在這里由于筆者水平有限就不對此展開討論,不過在學(xué)習(xí)中收集了幾篇關(guān)于“使用協(xié)議編程”方面的文章,有興趣的同學(xué)可以參考一下。
    1,從 Swift 的面向協(xié)議編程說開去
    2,我從55個Swift標準庫協(xié)議中學(xué)到了什么?
    3,Swift面向協(xié)議編程初探

文章最后

以上就是本人關(guān)于協(xié)議語法的心得,示例代碼在Swift3.0語法下都是編譯通過的,知識點比較雜,部分描述引自官方的文檔,另外協(xié)議作為一種強大的語法肯定還有很多值得我們?nèi)ヌ剿鳎疚牧谐龅闹R點僅僅涵括了部分內(nèi)容。如果文中有任何紕漏或錯誤歡迎在評論區(qū)留言指出,本人將在第一時間修改過來;喜歡我的文章,可以關(guān)注我以此促進交流學(xué)習(xí); 如果覺得此文戳中了你的G點請隨手點贊;轉(zhuǎn)載請注明出處,謝謝支持。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容