iT邦幫忙

2021 iThome 鐵人賽

DAY 12
0

協定的語法其實算是大量的使用在結構與類別中,尤其需要更底層的作用的時候,協定算是提供了一個共識,讓程式語言在撰寫的時候,可以根據一些基本認知去創建東西,過去一直都認為協定是一個更底層的東西,但這樣說其實很籠統,要說的話,它可以被認為是一種像共識一樣的東西,所有的內容都會基於這樣的共識去延伸進類別、結構、枚舉中。
而這樣的共識正反映在協定所建構的屬性、方法中。故,本篇章將分為幾個部分:

  1. 協定的意義
  2. 語法格式
  3. 對於屬性、方法的規範
  4. 協定之下的建構器

協定的意義

協定(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行所表示:
協定對於屬性的規範
協定不能定義一個屬性是儲存屬性或計算屬性,而只是定義屬性的名稱及是實體屬性或型別屬性。此外還可以定義屬性是唯讀或是可讀寫的。

  1. 協定定義屬性是可讀寫時,則遵循協定的型別定義的屬性不能是常數屬性或唯讀的計算屬性。
  2. 協定定義屬性是唯讀時,則遵循協定的型別定義的屬性可以是唯讀或依照需求改定義為可讀寫。(資料來源:Swift起步走)

繼上述的說法,也就是協定是可以在其功能中,將協定所規範的屬性定調為唯讀或可讀寫這兩種功能。

就上述之例子來說,可以讀寫的變數最後面的{ }裡面會有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()來處理。

tags: 鐵人賽

上一篇
# Day11--枚舉:讓你「有秩序」的管理「有順序」的項目
下一篇
# Day13--你到底愛不愛我?我們來解包這個Optional
系列文
Swift30天:從語法到觀念,告訴你在踏入實作前最好弄清楚的那些事30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言