Swift 的屬性系統極其強大,除存儲屬性外,計算屬性與屬性觀察器是實現數據綁定、UI 同步、邏輯封裝的核心工具。本文將系統講解兩者的語法、進階用法、常見陷阱及實戰模式。
struct Circle {
var radius: Double = 0
var area: Double {
get { .pi * radius * radius }
set { radius = sqrt(newValue / .pi) }
}
}
var(值可變)get 必須有返回值,set 參數默認名為 newValue,可自定義get,可省略 get 關鍵字)var diameter: Double { radius * 2 }
struct User {
var firstName = ""
var lastName = ""
var fullName: String {
get { "\(firstName) \(lastName)" }
set {
let parts = newValue.split(separator: " ")
firstName = String(parts.first ?? "")
lastName = String(parts.dropFirst().joined(separator: " "))
}
}
}
var user = User(firstName: "Tim", lastName: "Cook")
print(user.fullName) // "Tim Cook"
user.fullName = "Craig Federighi"
print(user.firstName) // "Craig"
print(user.lastName) // "Federighi"
enum Season {
case spring, summer, autumn, winter
var description: String {
switch self {
case .spring: return "春暖花開"
case .summer: return "夏日炎炎"
case .autumn: return "秋高氣爽"
case .winter: return "冬雪皚皚"
}
}
}
print(Season.autumn.description) // "秋高氣爽"
class Temperature {
var celsius: Double = 0 {
willSet { print("即將設置為 \(newValue)°C") }
didSet { print("已從 \(oldValue)°C 變為 \(celsius)°C") }
}
}
let t = Temperature()
t.celsius = 25
// 輸出:
// 即將設置為 25.0°C
// 已從 0.0°C 變為 25.0°C
willSet:值存儲前調用,參數 newValuedidSet:值存儲後調用,參數 oldValue| 特性 | 計算屬性 | 屬性觀察器 |
|---|---|---|
| 存儲 | 不存儲 | 存儲實際值 |
| 用途 | 衍生計算、雙向綁定 | 副作用(UI更新、日誌、持久化) |
| 可用於 | 類、結構體、枚舉 | 類、結構體(非 lazy、非計算) |
class Settings {
static let shared = Settings()
var volume: Float = 0.5 {
didSet {
UserDefaults.standard.set(volume, forKey: "volume")
NotificationCenter.default.post(name: .volumeChanged, object: volume)
}
}
private init() {
volume = UserDefaults.standard.float(forKey: "volume") // 不觸發 didSet
if volume == 0 { volume = 0.5 }
}
}
extension Notification.Name { static let volumeChanged = Notification.Name("volumeChanged") }
class ViewController: UIViewController {
lazy var tableView: UITableView = {
let tv = UITableView()
tv.dataSource = self
tv.delegate = self
return tv
}()
var items: [String] = [] {
didSet { tableView.reloadData() } // 觀察器觸發 UI 刷新
}
}
lazy 首次初始化、同值賦值(x = x 可能優化掉)。set 中手動觸發邏輯。mutating,觀察器同理。Swift 5.1+ 引入 @propertyWrapper,將觀察器邏輯封裝為可復用組件:
@propertyWrapper
struct UserDefault {
let key: String
let defaultValue: T
var wrappedValue: T {
get { UserDefaults.standard.object(forKey: key) as? T ?? defaultValue }
set { UserDefaults.standard.set(newValue, forKey: key) }
}
}
class Config {
@UserDefault(key: "darkMode", defaultValue: false)
static var darkModeEnabled: Bool
}
計算屬性封裝「如何計算」,屬性觀察器響應「何時變化」。兩者結合,構成 Swift 聲明式數據流的基石。實戰中:衍生數據用計算屬性,副作用用觀察器,通用邏輯用屬性包裝器,分層清晰,維護無憂。
下一期將探討 Swift 方法、下標與繼承機制,深入類型系統核心,敬請期待。