首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

Swift 核心語法(十):計算屬性與屬性觀察器 —— 構建響應式數據流的基石

     編輯:關於C語言

前言

Swift 的屬性系統極其強大,除存儲屬性外,計算屬性與屬性觀察器是實現數據綁定、UI 同步、邏輯封裝的核心工具。本文將系統講解兩者的語法、進階用法、常見陷阱及實戰模式。

一、計算屬性:不存儲值,只提供存取邏輯

1. 基本語法

struct Circle {
    var radius: Double = 0
    
    var area: Double {
        get { .pi * radius * radius }
        set { radius = sqrt(newValue / .pi) }
    }
}
  • 必須聲明為 var(值可變)
  • get 必須有返回值,set 參數默認名為 newValue,可自定義
  • 可只讀(僅 get,可省略 get 關鍵字)

2. 只讀計算屬性簡寫

var diameter: Double { radius * 2 }

3. 實戰:姓名拆分與合成

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) // "秋高氣爽"

三、屬性觀察器:監聽值變化的觸發器

1. 語法與調用時機

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:值存儲前調用,參數 newValue
  • didSet:值存儲後調用,參數 oldValue
  • 初始化過程中不觸發(構造器中直接賦值)
  • 構造器中調用屬性設置器會觸發

2. 觀察器與計算屬性的區別

特性計算屬性屬性觀察器
存儲不存儲存儲實際值
用途衍生計算、雙向綁定副作用(UI更新、日誌、持久化)
可用於類、結構體、枚舉類、結構體(非 lazy、非計算)

3. 實戰:UserDefaults 自動持久化

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 刷新
    }
}

五、常見陷阱與避坑指南

  1. 觀察器不觸發場景:構造器賦值、lazy 首次初始化、同值賦值(x = x 可能優化掉)。
  2. 計算屬性無法直接觀察:需在 set 中手動觸發邏輯。
  3. 結構體方法修改屬性需 mutating,觀察器同理。
  4. 避免在觀察器中做耗時操作(網絡請求、複雜計算),改為異步分發。

六、屬性包裝器預覽

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 方法、下標與繼承機制,深入類型系統核心,敬請期待。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved