6.%d Swift Study — Computed Property
目錄
⦿ 計算屬性
⦿ 書中的例子
⦿ getter、setter
⦿ Xcode
⦿ 最後設置
計算屬性
首先,看到下面的例子:
class GameCharacter { var hpValue: Double = 100
var defenceValue: Double = 300 var totalDefence: Double {
get {
return (defenceValue + 0.1 * hpValue)
}
set(levelUp) {
hpValue = hpValue * (1 + levelUp)
defenceValue = defenceValue * (1 + levelUp)
}
}
}let oneChar = GameCharacter()
print(oneChar.totalDefence)oneChar.totalDefence = 0.05
print("血量:\(oneChar.hpValue), 防禦力:\(oneChar.defenceValue)")
一個類別(class)建立後,宣告一個實體 oneChar
,此時將屬性 print 出來,會得到 300 + 0.1 * 100 = 310
;倘若今天將屬性設為 0.05
,屬性會依據這個設置做計算
,hpValue = 100 * 1.05 = 105;defenceValue = 300 * 1.05 = 315,這時,我們稱 totalDefence 為計算屬性
。
get{ } 用來存取(getter),set{ } 用來設置(setter)。
繼續閱讀|回目錄
書中的例子
再看到例子,如下:
class Square {
var width: Double = 0
var area: Double {
get {
return width * width
} set(newArea) {
width = sqrt(newArea)
}
}
}let bigSquare = Square()
bigSquare.width = 10
print(bigSquare.area)
同樣生成實體,將 width 設置為 10,此時存取 area 為 100.0,同樣是透過 getter 與 setter 對屬性做了計算。
getter 的 { } 裡的 return 是回傳計算結果,setter 的 { } 裡也是計算。
在這個例子裡,若 bigSquare.area = 81,print(bigSquare.width) 會得到 9.0(Double),因此,我們可以知道兩個屬性,width
跟 area
是環環相扣,並互相影響的,就因為 area
是計算屬性(Computed Property)。
繼續閱讀|回目錄
getter、setter
如果邊長 x 邊長
等於面積,邊長就等於面積開平方
,那麼,getter 與 setter 豈不是在說明同件事嗎?是的。
但 getter、setter 是互相影響的兩個函數嗎?不是,或者說問題不能這樣問。
當 area 被設定時會進到 setter,也就是 newArea 被設定了,那麼,width 也跟著被設定了;倘若 bigSquare 建立時未設定屬性,這時會進到 getter,存取這個 computed property 會得到 0,因為初始值為 0,這即是說 getter 與 setter 是分開作用的。
在第一段裡,兩個儲存屬性(hpValue、defenceValue)、一個計算屬性(totalDefence),兩個儲存屬性
都對計算屬性造成了影響,或者說計算屬性
靠他們初始化
。
從前面兩段的例子,在 set( ){ } 的參數,一個是 levelUp、一個是 newArea,( ) 都可以簡化不寫,以 Swift 的內部設定值 `newValue`
來改寫。
set {
hpValue = hpValue * (1 + newVlue)
defenceValue = defenceValue * (1 + newValue)
} set {
width = sqrt(newValue)
}
在 Swift 裡,我們學到許多這個語言的規則,例如計算屬性
的 `newValue`
,enum 的 rawValue 屬性,如此,enum 便可藉由 dot syntax
存取 case 的設定值,當 rawValue 為字串型別
時, .rawValue 還可直接得到與 case 相同的 String
。
在計算屬性中,getter 一定要有(像廢話,因為屬性通常得存取),setter 則不一定,雖然 getter 與 setter 同樣都是計算,只是一個沒有 newValue
,一個有。
繼續閱讀|回目錄
Xcode
計算屬性可以實作在什麼地方呢?
在 View Controller 下,若這樣設置:
var input: Double {
get {
return Double(resultLabel.text!)!
}
set {
resultLabel.text = "\(decimalPoint(rem: newValue))"
stillTyping = false
}
}
可以看到這個計算屬性,getter 裡面是用 Double 去轉換 label 的字串,也就是我們存取 input 時,會得到 String 型別轉成 Double 型別的數字。
在 setter 裡,label 的 text 是以 newValue 代入一個叫做 decimalPoint
的函式來獲取,這個函式是把 Double or Int 型別轉成 String,且如果這個 input 被設定時,stillTyping
就是 false
。
試想,這樣的設置可以用來做什麼事呢?
於是像這樣拉了一個 IBOutlet,兩個 IBAction,而 button 1、9 使用同一個 IBAction,我們可以透過 sender.currentTitle!
去存取你按的是 1 抑或是 9,而這跟在 Outlet Collection 中設置每個 button 為不同 tag 有些類似,tag 是為了區分
按下不同 button 時要做不同的事
,而 sender.currentTitle!
則是直接取用 button 設置的 title,當然,此時的 title 就是 String 型別的數字
。
當這兩顆 button 按下去,會直接給 resultLabel
賦值。
注意!並不是給 input 賦值,因為 \(input)
相當於存取 input,所以會使用 input 的 getter,而此時 input 是由 resultLabel.text 而來,只是轉成 Double 型別。
所以到這邊,我們幾乎可以確定 1 和 9 就是幫 resultLabel 轉成 Double。
接著,當按下 =
這個 button,會直接給 input 賦值,參照如下:
我們可以看到,當按下 button 1
,原先 label 顯示的 8 變成 8.0,這是因為 input 的型別為 Double,Double 回頭影響了 label。
而按下 =
,label 又變成了 666.0
,是因為 input 變為 666,又回頭影響了 label。(真的是這樣嗎?)
那麼,再度按下 button 1
或 9
呢?再怎麼按都是 666.0
,當然,回頭按 =
,也還是一樣 666.0
。
繼續閱讀|回目錄
最後設置
接著,稍微改變一下設置:
將前面說的 .currentTitle
拿來用,此時要記得,若當初設置 IBAction 時沒有選擇 UIButton,即 sender 是 Any,是沒有辦法用 dot syntax
去存取此屬性的。
最後結果如下:
在按完 1 後又想按 9,卻馬上回報錯誤,可以看到 8.0 是存取了 input 將 label.text 轉換成 Double,而 1 是 currentTitle,但按下 9(或再按 1) ,此時 input 沒辦法將 8.0 + 1
轉成 Double,自然會回報錯誤。
若要正常操作,需要將 currentTitle 也轉換為 Double,將加總結果再賦值給 label,如下:
我們再看看是否正常,如下:
於是可看到按 1 加 1,按 9 加 9,而按 = 就是又回到 666.0
,計算屬性是不是有點意思呢?
在這其中要特別注意的是 sender.currentTitle,必須要先經過 !
去 force unwrap
,在用 Double 將 String 轉型也還需要一次 !
由於 Swift 的安全檢查,避免在做轉型的時候出錯,當你 force unwrap 時,Xcode 也會提供解決辦法。如下:
第二個解決辦法便是確定有值,所以取值,實際上程式寫成不能轉型成double便會回報錯誤。
第一個解決辦法是無值時候設置初值,如下:
如果你確定 sender.currentTitle 確定有值就放心地 unwrap,而 Double 將 String 轉型若不是那麼確定,就給定一個初值為 0,經過修改後,APP 便比較安全(不容易當)了。
這次就分享到這,感謝您的閱讀。
繼續閱讀|回目錄
附上 Reference: