還記得上一篇介紹到 Stored Property
以及 Computed Property
,也學習到如何使用 lazy
前綴字的使用,今天我們來介紹剩下兩種屬性取值的方式:
Type Property
Property Observer
型別屬性,簡單來說就是只有 Type 本身能夠使用,不能透過實體來調用,然而要定義 Type Property 的話,必須在 Property 前方加上 static
前綴字:
struct Environment {
static let testing = "testing-mock.com"
static let staging = "staging-mock.com"
let production = "production-real.com"
}
在使用時,我們就可以值就透過 Environment
本身來使用屬性,在 compiler time 時就已經決定好,把資料放在同一個記憶體,這麼做有一個好處就是可以共享同一個資源:
Environment.testing
Environment.staging
因為 production
並沒有加上 static
所以就不能直接用型別本身來調用,除非我們再建立一個實體,就可以使用 production
,但是如果用實體就不能使用 static property。
let env = Environment()
env.production
不只 Struct 可以使用,在 Enum 以及 Class 中都是可以使用 Static Property。
enum Sex {
static var male = "男生"
static var female = "女生"
}
class Math {
static let pi = 3.14159
static var eularsNumber: Double {
2.718281828459045235
}
}
還記得在前一篇提到的 Computed Property,這邊是只使用了 getter,這時候 eularsNumber
就變成 get-only property ,不能被指派值。
除了使用 static
使得 property 變成 type property 之外,你還可以使用 class
。
class 與 static 很相似,假使在類別中,差別在於 static 不允許子類別複寫父類別的屬性,class 可以:
class 車 {
var 輪胎數量 = 4
class var 顏色: String {
"黑色"
}
}
class 超級跑車: 車 {
override class var 顏色: String {
"銀色"
}
}
但是假使我在子類別中,想要 override 父類別中不是 class property,就會發生錯誤:Cannot override with a stored property '輪胎數量'
不只可以使用型別屬性,也可以使用型別方法:
定義在特定型別的方法,只屬於類別本身,不能被實體調用
class 食死人 {
static func 阿瓦達索命咒() {
print("Avada Kedavra!!!")
}
}
可以使用 食死人.阿瓦達索命咒()
呼叫,但是如果是先實作 食死人 類別,再去呼叫,就會出現警告標語。
食死人.阿瓦達索命咒() //Good
let 我是食死人 = 食死人()
我是食死人.阿瓦達索命咒() //Static member '阿瓦達索命咒' cannot be used on instance of type '食死人'
而且 Static Functions 不能被覆寫。
class 貝拉・雷斯壯: 食死人 {
override func 阿瓦達索命咒() { //Method does not override any method from its superclass
print("我是壞蛋,Avada Kedavra!!!")
}
}
class 食死人 {
class func 阿瓦達索命咒() {
print("Avada Kedavra!!!")
}
}
Class Functions 跟 Static Functions 很像,差在 Class Functions 允許子類別覆寫父類別的方法。
這時候 貝拉・雷斯壯 就有客製的阿瓦達索命咒了。
class 貝拉・雷斯壯: 食死人 {
override class func 阿瓦達索命咒() {
print("我是壞蛋,Avada Kedavra!!!")
}
}
但是方法一樣只屬於類別本身,不允許實體調用。
透過觀察屬性的變化來實作不同的事情,我們可以透過 Property Observers 來完成,有兩種觀察方式:
didSet
:在屬性有變動之後willSet
:在儲存值之前舉個範例:
class 倒數工具 {
var 剩餘天數 = 100 {
willSet(最新剩餘天數) {
print("還剩下 \(最新剩餘天數) 天")
}
didSet(舊有天數) {
if 舊有天數 >= 剩餘天數 {
print("減少了 \(舊有天數 - 剩餘天數) 天")
} else {
print("超出原有天數")
}
}
}
}
let tool = 倒數工具()
tool.剩餘天數 = 37
// 還剩下 37 天
// 減少了 63 天
也是可以省略帶入參數,如果不帶入參數
willSet
中,使用 newValue
didSet
中,使用 oldValue
class 倒數工具 {
var 剩餘天數 = 100 {
willSet {
print("還剩下 \(newValue) 天")
}
didSet {
if oldValue >= 剩餘天數 {
print("減少了 \(oldValue - 剩餘天數) 天")
} else {
print("超出原有天數")
}
}
}
}
let tool = 倒數工具()
tool.剩餘天數 = 37
// 還剩下 37 天
// 減少了 63 天