iT邦幫忙

2021 iThome 鐵人賽

DAY 8
0

在上一篇的文章中,有提到屬性(property)這件事情指的就是類別或結構裡面的所包含的變數、常數,而方法(method)就是類別、結構裡面的函式。

而實質上,論及屬性這件事情,有以下這四種的屬性:

  1. 儲存屬性(stored property):在實體內儲存常數或變數,可以用於類別及結構。
  2. 計算屬性(computed property):在實體內計算一個值,可以用於類別、結構及列舉。
  3. 型別屬性(type property):與前兩個不同,這是屬於型別本身的屬性。
  4. 屬性觀察器(property observer):用來觀察屬性值的變化,並以此觸發一個自定義的操作。(資料來源:Swift起步走)

以下,將會分別描述這四種屬性的特質:

屬性

  1. 儲存屬性
    儲存屬性應該算是最簡單的概念,它就是可以把值存進去裡頭,比較精準的說法應該是:儲存在特定型別(類別或結構)的常數或變數。
    而作為用「儲存」一詞來形容,也就意味著可變;在一開始的時候,結構或類別的設定只給定所謂的預設值、型別,然而在過程中,是可以經過修改、儲存等變動的。

如上述,在將Room404實體化後,我們便可以針對它的city這個項目來做一些內容性的更動。而這個時候打印出來的Room404的city就被改動了。
然而,上述的這個前提是建立在Room405的宣告是變數(variable)的情況,假若你今天宣稱是常數(constant),那就等著報錯吧,因為常數是無法更改的啊!:

  1. 計算屬性
    計算屬性的功用則是不存取值,而是以get、set兩個關鍵字來存取值、或來設置其他屬性的值
  • get:存取值
  • set:設置其他屬性的值

如上述,get會做的事情就是讓值被儲存,所以可以看到右邊列跑出了130,也就是被計算的值。

而set在做的事情則是設置其他屬性的值,如上述,set( )中間傳入了leveup,而在set內部則對HP內部進行了改變,也就是上升一個等級後,它就會增加它的血量,防禦力也如是。(資料來源:Swift起步走、the swift programming language)

不過,關於100Days of Swift中所描述的計算屬性則有一個不一樣的例子:

總之,這個例子主要要談的內容是,我們可以創造一個屬性,這個屬性裡面可以有一些描述的計算,無論是if…else也好或whatever,它可以因此帶入內部的其他屬性進入這個屬性裡被使用,且因此從這個屬性裡輸出這個屬性的結果。

  1. 型別屬性(type property)
    Swift起步走上對於型別屬性的描述大概是這樣:
    型別屬性(type property)是屬於這個型別(類別、結構或列舉)的屬性,無論生成了多少這個型別的實體,型別屬性都只有唯一一份。
    型別屬性使用於定義所有從這個型別生成的實體共享的資料。
    換句話說,就是型別屬性是不變的,無論在有多少個化為實體,型別屬性會是不變的。
    而型別屬性如果是儲存屬性的話,則必須有預設值,如下的armysize = 0
    儲存型的型別屬性是延遲初始化的,只有在第一次被呼叫時才會被初始化,所以不需要對其使用lazy。
    而就以下的例子,「型別屬性是使用static關鍵字作宣告變數或常數。」

總之,我們在產出了兩個實體Tom & Leo後,我們的Armor就會自己對於其進行計算。

  1. 屬性觀察器
    屬性觀察器這件事情很有趣,它是一個具有時間性的東西,在Swift起步走上面的描述是這樣:
    屬性觀察器(property observer)會監控和回應屬性值的變化,每次屬性被設置新的值都會呼叫屬性觀察器。
    而屬性觀察器的建構分別由以下二者:
  • willSet:在設置新的值之前呼叫,會將這個新的值當做一個常數參數傳入,如果不命名這個參數名稱時,會有一個內建的參數名稱newValue。
  • didSet:在新的值被設置之後立即呼叫,會將舊的屬性值當做參數傳入,這個參數可以自己命名,或直接使用內建的參數名稱oldValue。

總和上述,didSet的用途,其實主要是就是讓新的屬性能夠被傳進去參數裡面,然後藉由值的傳入去更動整個狀態(我好像大概知道進度條要怎麼寫了XD)
而willSet則是在所有事情發生前,會有一個值被當作類似默認的存在描述。
套用100 Days of Swift的例子:

總之,上面的程式碼會打印出下面這個:

不過,據Paul Hudson認為:willSet是一個很少用的函式。
但不論如何,還是來試一下willSet:

總之,在這個案例中,hp是沒有變化的,因為還沒有敘述如何讓血量減少的功能,或許往後會有機會嘗試。

方法

繼上述談到所謂的屬性後,可以了解struct、class中有屬性也有方法,而方法這個東西,大致在概念上一分爲二:實體方法、型別方法

實體方法(instance method):先需要生成一個特定型別(類別、結構或列舉)的實體,才能使用這個實體裡的方法。
型別方法(type method):屬於特定型別(類別、結構或列舉)本身的方法。

  1. 實體方法
    實體方法需要做的事情,就是先在類別或結構裡面詳述方法內含什麼:

Mutating methods

100 Days of Swift-Mutating method的相關描述:

The problem is that when you create the struct Swift has no idea whether you will use it with constants or variables, so by default it takes the safe approach: Swift won’t let you write methods that change properties unless you specifically request it.

翻譯翻譯:當你創建 struct 時,Swift 不知道你是將它與常量還是變量一起使用,所以在默認情況下它將採用一個安全的方法:除非你特別要求,否則 Swift 不會讓你編寫改變屬性的方法。

When you want to change a property inside a method, you need to mark it using the mutating keyword,

所以,當你需要改變一個方法裡面的屬性的時候,你需要標示”Mutating”

Swift起步走的相關描述:

一般情況下,一個值型別(結構或列舉)實體的屬性,不能在它的實體方法中被修改。但如果有特殊需求需要修改屬性,可以使用變異(mutating)這個方法。要使用變異方法,將關鍵字mutating放在方法的func之前就可以了,如下:

我們在這邊使用mutating func ,可以讓原先的屬性內容被改變
或許這裡有更好的例子:

這邊如果用mutating func的話,就會讓someone的內容跟之前的預設去做改變,可能要體會一下。

  1. 型別方法
    形別方法有別於實體方法,為定義在特定型別(類別、結構與列舉)上的方法,它不是屬於實體,而是屬於這個型別(類別、結構與列舉)上的方法。
    什麼意思呢?
    可以這樣說,就是class裡面有class func ,所以它不是一種實體。

或是用static func來做也是可行的。

總之,型別方法不需要生成實體,就可以直接呼叫型別方法,因為型別方法是屬於一個特定型別(類別、結構與列舉),而非一個實體。

綜合上述,我們討論到三件事情,一是實體方法的使用,它必須經過實體話,才能以「實體.方法()」的方式來呼叫,而型別方法因為本身的構成是類別、結構裡面含有型別方法,所以只要在外部將「類別.型別方法()」,拿出來使用就可以了。

而變異方法Mutating func則是在實體方法中,假若要在定義過的實體外部進行更動的話,就可以在類別、結構內部先設置一個變異方法,然後在外部套用,就會變成Mutating func所指定的內容。

tags: 鐵人賽

上一篇
# Day7--物件兄弟黨:類別與結構
下一篇
# Day9--老爸,我可以繼承你的家產,但我不想長得太像你
系列文
Swift30天:從語法到觀念,告訴你在踏入實作前最好弄清楚的那些事30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言