深入理解Swift中的Class和Struct
Class和Struct是Swift中很重要的兩種資料結構,同時也是Swift面試題必問的一道題。所以對Class和Struct理解透徹對我們學習Swift有很大的幫助。
理解Class
Class的定義和使用
class Animal { var name: String? var weight = 0.0 } let cat = Animal() cat.name = "cat" cat.weight = 10 print("cat's name: \(cat.name!), cat's weight: \(cat.weight)") //cat's name: cat, cat's weight: 10.0 複製程式碼
Class是引用型別
當值傳遞的時候,它是傳遞對已有instance的引用。下面用程式碼來解釋一下這句話:
let cat = Animal() cat.name = "cat" cat.weight = 10 let blackCat = cat blackCat.name = "blackCat" print("cat's name: \(cat.name!)") // cat's name: blackCat 複製程式碼
通過上面的程式碼可以瞭解到,其實 cat
和 blackCat
指向的是同一個Animal的instance。它們只是這個instance的兩個不同的名字而已。如下圖所示:

Note
我們看到上述程式碼把 cat
和 blackCat
宣告為了 let
,但是我們依然可以修改它的屬性,因為 cat
和 blackCat
引用的instance並沒有改變,它們還是引用之前instance,我們只是修改的instance的屬性。但是不能將 cat
或者 blackCat
指向另一個例項,如 blackCat = Animal()
會提示 Cannot assign to value: 'blackCat' is a 'let' constant
的錯誤。
Identity Operators
Swift 提供 ===
和 !==
來判斷兩個變數或者常量是不是引用同一個instance(只用於class,想一想為什麼struct不需要).
if blackCat === cat { print("Identical") //Identical } else { print("Not identical") } 複製程式碼
===
和 ==
是不一樣的。
=== == ==
class Animal { var name: String? var weight = 0.0 } extension Animal: Equatable { static func == (lhs: Animal, rhs: Animal) -> Bool { return lhs.name == rhs.name && lhs.weight == rhs.weight } } let cat = Animal() cat.name = "cat" cat.weight = 10 let blackCat = cat blackCat.name = "catName" let whiteCat = Animal() whiteCat.name = "catName" whiteCat.weight = 10.0 if blackCat === cat { print("Identical") //Identical } else { print("Not identical") } if whiteCat === blackCat { print("Identical") } else { print("Not identical") //Not identical } if whiteCat == blackCat { print("Equal") } else { print("Not Equal") //Equal } 複製程式碼
理解Struct
Struct的定義和使用
struct FPoint { var x = 0.0 var y = 0.0 //當在struct修改屬性的時候需要使用mutating mutating func addX(add: Double) { self.x = self.x + add } } let p1 = FPoint() print("p1's x : \(p1.x), p1's y: \(p1.y)") // p1's x : 0.0, p1's y: 0.0 複製程式碼
Struct是值型別
當值進行傳遞的時候,它會copy傳遞的值。下面用程式碼來解釋一下這句話:
var p2 = p1 p2.x = 3.0 print("p1's x : \(p1.x), p1's y: \(p1.y); p2's x : \(p2.x), p2's y: \(p2.y)") //p1's x : 1.0, p1's y: 2.0; p2's x : 3.0, p2's y: 2.0 複製程式碼
通過上述程式碼我們可以看到,將 p1
賦值給 p2
之後改變 p2
的值並不會影響 p1
的值,這是因為在將 p1
賦值給 p2
的時候是拷貝一個instance 值與p1相同
,然後將拷貝的instance賦值給 p2
。如下圖所示:

Note
如果struct的instance宣告為let,是不能改變instance的值的。如
let p1 = FPoint(x: 1.0, y: 2.0) p1.x = 10.0 //報錯:Cannot assign to property: 'p1' is a 'let' constant 複製程式碼
在專案中如何選擇Struct和Class
- 預設使用struct
- 當你需要繼承Objective-C某些類的的時候使用class
- 當你需要控制唯一性時使用class
- 使用struct和protocol來實現model繼承和共享行為,如下程式碼所示:
protocol AnimalCommonProtocol { var name: String? { get set } var weight: Double { get set } func run() } struct Cat : AnimalCommonProtocol { func run() { print("cat run") } var name: String? var weight: Double var gender: String? } struct Dog : AnimalCommonProtocol { func run() { print("dog run") } var name: String? var weight: Double var type: String? } 複製程式碼
總結起來就是一句話:能使用struct就不要使用class
為什麼優選struct
- 使用struct不需要考慮記憶體洩漏和多執行緒讀寫的問題,因為在傳遞值的時候它會進行值的copy
- struct儲存在stack中,class儲存在heap中,struct更快