協定的語法其實算是大量的使用在結構與類別中,尤其需要更底層的作用的時候,協定算是提供了一個共識,讓程式語言在撰寫的時候,可以根據一些基本認知去創建東西,過去一直都認為協定是一個更底層的東西,但這樣說其實很籠統,要說的話,它可以被認為是一種像共識一樣的東西,所有的內容都會基於這樣的共識去延伸進類別、結構、枚舉中。
而這樣的共識正反映在協定所建構的屬性、方法中。故,本篇章將分為幾個部分:
協定(protocol)是 Swift 一個重要的特性,它會定義出為了完成某項任務或功能所需的方法、屬性,協定本身不會實作這些任務跟功能,而僅僅只是表達出該任務或功能的名稱。這些功能則都交由遵循協定的型別來實作,列舉、結構及類別都可以遵循協定,遵循協定表示這個型別必須實作出協定定義的方法、屬性或其他功能。(資料來源:Swift起步走)
有點像是協定定義出一個To Do List,而所有遵循協定的型別都必須照表操課,將需要的功能都實作出來。
Protocols are a way of describing what properties and methods something must have. You then tell Swift which types use that protocol — a process known as adopting or conforming to a protocol.
協定是一種方法去描述什麼樣的屬性、方法在其裡面必須擁有,你接著告訴Swift什麼樣的型別使用那樣的協定,這被稱為採用或遵守協議的過程。
綜合上述,協定的功能就是提供一個原則,讓它完成某個任務,而這些原則規範了某項任務所需要的方法、屬性,但協定不會實作這些任務與功能。協定所提供的,就是一個原則,讓結構(struct)、類別(class)、枚舉(Enum)來遵守。受協定約束的這些型別,必須實作出受制於其定義的方法、屬性等功能。
在第1–3行(或第5–7行)中,基本上提供的是協定的最基本樣態
如若是結構要使用協定,則以第9–11行為內容,提出結構名稱後,便以冒號“:”(colon)隔開,再接著協定的名稱,如若有複數個協定需要遵守,則以逗號“,”(comma)來作為協定間的區隔。
其實類別的協定寫作的方式幾乎跟結構相似,但結構沒有所謂的父子類別的功能,所以類別在表示時,先以「子類別:父類別」,這樣的語法開頭,隨後,在父類別旁邊以“,”繼續將所需要的協定引入,如上述第17–19行所表示:
協定對於屬性的規範
協定不能定義一個屬性是儲存屬性或計算屬性,而只是定義屬性的名稱及是實體屬性或型別屬性。此外還可以定義屬性是唯讀或是可讀寫的。
繼上述的說法,也就是協定是可以在其功能中,將協定所規範的屬性定調為唯讀或可讀寫這兩種功能。
就上述之例子來說,可以讀寫的變數最後面的{ }裡面會有get、set兩者
而唯讀的就只有get字樣
實例來說:
變數Name就是一個唯讀的例子,而具有協定的結構,則必須要因著協定的設定,而將其內部所設定的屬性放進去結構裡設定。
協定可以定義實體方法或型別方法以供遵循,而這些方法不需要大括號{}以及其內的內容(即不需要實作),而實作則是交給遵循協定的型別來做。
協定可以定義含有可變數量參數(variadic parameter)的方法。
協定不能為方法的參數提供預設值。
與屬性的規則一樣,協定中要定義型別方法時,必須在前面加上static關鍵字。而當一個類別遵循這個協定時,除了static還可以使用class關鍵字來定義類別的這個型別方法。(資料來源:Swift起步走)
協定定義方法的時候,是不需要{ }作為內容:
只需要:
把定義的方法寫出來就可以了。
所以,在實際上的例子上,我們可以見到,我們在協定裡面所寫好的內容,就會在實際的類別使用上變成是類別必須要設定方法的內容,假若沒有依照協定所給定的屬性、方法下去寫,則會報錯。
上述對於協定中的方法有了基本的討論後,接下來會提到的就是變異方法:
使用mutating關鍵字放在func關鍵字前來定義變異方法(變異方法表示可以在方法中修改它所屬的實體以及實體的屬性的值)。
遵循一個包含變異方法的協定時,列舉跟結構定義時必須加上mutating關鍵字,而類別定義時則不用加上。(資料來源:Swift起步走)
總之,在舉出變異方法時,變異方法是可以修改實體以及屬性的值的,不過,變異方法在結構、枚舉上與類別上則有兩者不同的區別:
在協定中有變異方法時:
結構、枚舉定義必須加上mutating
類別定義則否
以下則一實例:
就以enum case作為是一個變異的方法來討論,我們可以直接看到第5行的地方舉了兩個case:A、B,而SomeEnum中必須要有mutating func someMethod( )在裡面,其中為一個假如遇到A,就變成B,遇到B,就變成A的案例。
所以,在實體transition裡面,就是case.A,然後加入someMethod( )後,就會變成B
所以,變異方法在使用上,就是一個可以改變屬性的方法,如果遇到需要變異的情況,可以大方的使用。
如果是一個類別遵循一個含有建構器的協定時,無論是指定建構器或便利建構器,都必須為類別的建構器加上required修飾符,以確保所有子類別也必須定義這個建構器,從而符合協定(如果類別已被加上final,則不需要為其內的建構器加上required,因為final類別不能再被子類別繼承)(資料來源:Swift起步走)
也就是說,我們假若今天創建一個協定後,而這個協定裡面具有建構器,無論是指定或便利建構器,我們都必須在類別裡面的建構器加上required字樣:
如果一個子類別覆寫了父類別的指定建構器,且此建構器滿足了某個協定的要求,則該建構器必須同時加上required和override,如下:
所以,如果是基於具有協定的情況下,我們若要在子類別中覆寫父類別的內容,我們的建構器就必須要有三個字樣:required、override、init( ),這三樣齊全,才是覆寫父類的子類建構器應有的樣子。
綜合本篇章所提及的內容,以下有三個重點會提及:
本篇章首先提到的是協定的運作方式,協定主要制定的是讓結構、枚舉、類別遵守的屬性、方法的規範,假若在協定中有提到關於屬性、方法在其中,使用該協定的結構、枚舉、類別就應該在其內容中有該屬性與該方法的存在。
協定可以是唯讀(get),也可以是可讀寫(set)的兩種狀態,端看設計者如何應用。
協定中如果具有建構器,在子類別中需要註明required,而假若需要覆寫父類建構器的內容,則以required override init()來處理。
鐵人賽