Swift 類別 (Classes) 教學
雖然 Swift 大力推崇 Struct,但 類別 (Class) 仍然有其無法取代的地位。在處理與 Objective-C 的相容性、需要繼承架構、或是需要共享單一實例狀態時,我們仍然必須使用 Class。
定義類別
使用 class 關鍵字定義。語法與 Struct 非常相似,但要注意 Class 沒有自動產生的 Memberwise Initializer,你通常需要自己寫 init。
class VideoMode {
var resolution = Resolution() // 假設 Resolution 是一個 Struct
var interlaced = false
var frameRate = 0.0
var name: String?
// Class 通常需要自行定義 init,除非屬性都有預設值
init(name: String) {
self.name = name
}
}
參考型別 (Reference Types) 的意義
Class 是參考型別 (Reference Type)。這意味著變數儲存的不是物件本身,而是指向記憶體中那個物件的指標 (Pointer)。
什麼是「參考型別」?
當你把一個 Class 實例賦值給另一個變數時,不會複製內容,而是共享同一個實例。
生活類比: 想像你和同事共用一份 Google Sheet (雲端試算表)。你只是把「連結 (URL)」傳給同事。當同事透過連結進去修改了資料,你螢幕上看到的內容也會跟著改變。因為你們看的是同一份文件。
let tenEighty = VideoMode(name: "1080p")
tenEighty.frameRate = 25.0
let alsoTenEighty = tenEighty // 這裡只是複製了「參考 (連結)」
alsoTenEighty.frameRate = 30.0 // 修改了這個參考指向的物件
print(tenEighty.frameRate) // 30.0 (原本的變數也被影響了!)
恆等運算子 (Identity Operators)
因為 Class 是共享的,有時候我們需要知道兩個變數是不是指向同一個實例。Swift 提供了 === (恆等) 和 !== (不恆等) 運算子。
if tenEighty === alsoTenEighty {
print("這兩個變數指向同一個 VideoMode 實例")
}
=== (是否指向同一記憶體位置) 和 == (內容是否相等) 是完全不同的概念。Class 獨有的功能
以下功能是 Struct 做不到,專屬於 Class 的:
繼承 (Inheritance):一個類別可以繼承另一個類別,獲得其屬性與方法。(詳見 類別繼承)
型別轉換 (Type Casting):可以在執行時期檢查 (
is) 或轉換 (as) 實例的型別。解構器 (Deinitializers): Class 可以定義
deinit方法。當一個實例被釋放 (記憶體回收) 前,deinit會被自動呼叫。這通常用來釋放非 Swift 管理的資源 (如檔案開啟、Notification 移除)。class Player { deinit { print("Player 被釋放了,可以在這裡做清理工作") } }參考計數 (Reference Counting): Swift 使用 ARC (Automatic Reference Counting) 來管理 Class 的記憶體。允許多個參考指向同一個實例。
總結:Struct vs Class 如何選擇?
這是一個經典的面試題,也是架構設計的關鍵。
| 特性 | Struct (結構) | Class (類別) |
|---|---|---|
| 型別語意 | Value Type (值型別) | Reference Type (參考型別) |
| 資料傳遞 | 複製 (Copy) | 傳遞參考 (Share) |
| 記憶體位置 | Stack (堆疊) - 較快 | Heap (堆積) - 較慢 |
| 繼承 | 不支援 | 支援 |
| Mutating | 修改屬性需加 mutating | 不需要 |
| 主要用途 | 資料模型 (Model), SwiftUI View | 共用狀態管理器 (ViewModel), 舊版 UIKit |
黃金準則:預設使用 Struct。 只有當你需要「共享狀態」或「繼承」時,才使用 Class。