Class 類
類與結構體非常相似洒嗤,我們都用它創(chuàng)建具有屬性和方法的新數據類型粗俱。但是類引入了一個新的,重要而且復雜的功能-繼承澳化,使一個類建立在另一個類的基礎上的能力崔步。
繼承是一個強大的功能稳吮,但是請記住要使代碼保持簡單:功能存在缎谷,但不意味著你需要使用它。
“任何傻瓜都可以編寫計算機可以理解的代碼灶似,但是優(yōu)秀的程序員可以編寫人類可以理解的代碼列林。”——Martin Fowler酪惭。
SwiftUI中廣泛使用結構體希痴,而數據中廣泛使用了類。
與以前使用UIKit時春感,是非常不同的砌创,UIKit中我們使用類進行UI設計,而使用結構體進行數據處理鲫懒。
1.創(chuàng)建類
類與結構體的第一個區(qū)別就是嫩实,類中不會帶有默認的成員初始化器。如果類中有屬性窥岩,則必須創(chuàng)建自己的初始化方法甲献。
class Dog {
var name: String
var breed: String
init(name: String, breed: String) {
self.name = name
self.breed = breed
}
}
let poppy = Dog(name: "Poppy", breed: "Poodle")
創(chuàng)建類的實例看起來和結構體一樣。
為什么Swift要有類和結構體?
它們之間有五個重要的區(qū)別颂翼,后面我們詳細解釋這些差異晃洒。
1.類不帶有合成的成員初始化器。
2.類可以通過繼承朦乏,從而獲得另一個類的屬性和方法球及。
3.結構體的副本始終是唯一的,而類的副本實際上指向相同的共享數據呻疹。
4.類具有反初始化器吃引,當類的實例被銷毀時,會調用這些方法诲宇,而結構體不會际歼。
5.常量類中的變量屬性可以自由修改,而常量結構體中的變量不能隨意修改姑蓝。
2.類的繼承
類與結構體的第二個區(qū)別鹅心,就是你可以基于現有類創(chuàng)建另一個類,它繼承了原始類的所有屬性和方法纺荧,并且可以添加自己的屬性和方法旭愧。
這稱為類的繼承或者子類化颅筋,被繼承的類稱為"父類"或“超類”,新的類稱為“子類”输枯。
基于剛才我們創(chuàng)建的類议泵,我們創(chuàng)建一個Poodle
類
class Poodle: Dog {
init(name: String) {
super.init(name: name, breed: "Poodle")
}
}
因為Poodle具有自己固定的品種,所有我們提供了一個僅需要name的初始化方法桃熄。
Swift總是要求在子類調用 super.init
方法先口,防止父類在創(chuàng)建時做一些重要工作。
為什么類不具有成員初始化器瞳收?
因為類有繼承碉京,使得成員初始化方法很難使用,當繼承一個類后螟深,然后在子類中添加了一些屬性谐宙,此時父類的成員初始化方法在子類中將不再有用,所以界弧,Swift讓我自己提供成員初始化方法凡蜻。不管添加任意數量的屬性,都不影響類的繼承垢箕。
3.重載 override
子類可以用自己的實現替換父類方法划栓。
比如下面這個帶有makeNoise()
方法的普通類。
class Dog {
func makeNoise() {
print("Woof!")
}
}
我們創(chuàng)建一個繼承的新類舰讹。通過重載override func
父類方法茅姜。
class Poodle: Dog {
override func makeNoise() {
print("Yip!")
}
}
let poppy = Poodle()
poppy.makeNoise()
更改后,poppy.makeNoise()
將打印“Yip!”月匣。
4.final class
如果你不想讓其他類繼承你的類钻洒,你可以將類聲明為final,其它類將不能繼承锄开。
在類前添加final:
final class Dog {
var name: String
var breed: String
init(name: String, breed: String) {
self.name = name
self.breed = breed
}
}
final以前可以帶來一點點的性能提升素标,更重要的是final讓人更容易理解你的代碼。
5. Copy
類與結構體的第三個區(qū)別是Copy萍悴。結構體拷貝后头遭,原始和復制的結構體是不同的,改變一個不會更改其它的結構體癣诱,而類原始副本和復制副本指向了同一個事物计维,因此更改一個會更改另一個。
class Singer {
var name = "Taylor Swift"
}
var singer = Singer()
print(singer.name)
var singerCopy = singer
singerCopy.name = "Justin Bieber"
print(singer.name)
我們看到singer的名字已經變化撕予。
如果改為結構體鲫惶,兩次將打印相同的結果。
為什么類要共享數據实抡?
類的副本共享基礎數據欠母,結構體始終具有自身的唯一數據欢策。
這種區(qū)別叫做“值類型與引用類型”。結構體是值類型赏淌,類時引用類型踩寇。
結構體的值萬千包含在變量內,而引用類型復制時六水,會獲得一個新的指針俺孙,指向原始對象所在的內存。
Swift人員更喜歡將結構體用于自定義類型缩擂,比如在一個大型程序中共享一個user對象時鼠冕,如果使用的是類,有人把user數據改掉卻不知道時胯盯,很可能會遇到問題。
有時候將要共享的東西计露,使用類改變時并通過一些方式發(fā)送消息給其他人博脑,可能比拷貝一些對象更好一些。
6.Deinit
類和結構體之間的第四個區(qū)別是票罐,類具有反初始化叉趣,在類被銷毀時運行。
class Person {
var name = "John Doe"
init() {
print("\(name) is alive!")
}
func printGreeting() {
print("Hello, I'm \(name)")
}
deinit {
print("\(name) is no more!")
}
}
類為什么有deinit?
因為類的復制行為该押,很難判斷類何時被銷毀,Swift有”自動引用計數“的操作疗杉,ARC自動跟蹤類的副本,當每次獲得一個副本蚕礼,Swift對其引用計數+1,每次被銷毀時烟具,Swift對其引用計數中-1,計數為0時,Swift調用反初始化程序并銷毀該對象奠蹬。
結構體有其自己的副本朝聋,不需要反初始化。
7.類的Mutability
類與結構體最終區(qū)別是囤躁,處理常量的方式冀痕。常量的結構體,屬性不能更改狸演,而類可以言蛇。
類不需要mutating關鍵字。
為什么可以更改常量類中的變量屬性?
原因在于宵距,一個指向的是內存中的某些數據腊尚,而另一個指向值。
結構體更改屬性時消玄,實際上是在更改整個結構跟伏。而類不會破壞并重新創(chuàng)建值丢胚。所以常量類可以自由更改變量屬性。
8.總結
1.類和結構體類似受扳,都可以使用屬性和方法創(chuàng)建自己的類型携龟。
2.一個類可以從另一類繼承,并獲得父類所有屬性和方法勘高。
3.final關鍵字標記一個類峡蟋,阻止其它類繼承。
4.通過重寫华望,子類可以使用新的實現替換父類方法蕊蝗。
5.當兩個變量指向同一個實例時,他們指向同一塊內存赖舟。
6.類有deinit,銷毀時運行蓬戚。
7.將屬性聲明為變量時,無論類實例為常量或變量宾抓,都可以更改屬性子漩。