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

Swift 進階特性(九):延遲存儲屬性 —— 按需初始化的性能優化利器

     編輯:關於C語言

前言

在 iOS/macOS 開發中,某些屬性的初始化開銷極大(如解析大型 JSON、創建複雜視圖層級、建立數據庫連接),若在對象構造時一律初始化,會嚴重拖慢啟動速度與內存佔用。Swift 的 延遲存儲屬性 完美解決此痛點:首次訪問時才計算初始值。

一、語法與規則

class DataLoader {
    // 必須用 var,不能用 let
    lazy var expensiveResource: HeavyResource = {
        print("🔧 正在初始化昂貴資源...")
        return HeavyResource()
    }()
}
關鍵點:
  • 關鍵字 lazy 修飾
  • 必須聲明為 var(常量 let 需在構造完成前確定值)
  • 初始化閉包結尾的 () 表示立即執行閉包並賦值結果
  • 線程不安全:多線程並發首次訪問可能導致多次初始化(需自行加鎖或使用 dispatch_once 模式)

二、典型應用場景

1. 昂貴對象持有(如圖片緩存、數據庫連接)

class ImageCache {
    lazy var cache: NSCache = {
        let c = NSCache()
        c.countLimit = 100
        c.totalCostLimit = 50 * 1024 * 1024 // 50MB
        return c
    }()
}

2. 視圖控制器中的子視圖/子控制器

class ProfileVC: UIViewController {
    lazy var headerView: ProfileHeaderView = {
        let v = ProfileHeaderView()
        v.delegate = self
        return v
    }()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        view.addSubview(headerView) // 首次訪問觸發創建
    }
}

3. 依賴外部上下文的屬性(如需 self 的閉包)

class NetworkManager {
    lazy var session: URLSession = {
        let config = URLSessionConfiguration.default
        config.timeoutIntervalForRequest = 30
        return URLSession(configuration: config, delegate: self, delegateQueue: nil)
    }()
}

三、實戰對比:有無 lazy 的性能差異

class Bird {
    let name: String
    init(name: String) {
        self.name = name
        print("🐣 Bird \(name) 初始化")
        Thread.sleep(forTimeInterval: 2) // 模擬耗時操作
    }
}

class Ostrich {
    let name = "鴕鳥"
    var bird = Bird(name: "鳥類") // 非 lazy,構造時立即初始化
}

class LazyOstrich {
    let name = "鴕鳥"
    lazy var bird = Bird(name: "鳥類") // lazy,首次訪問才初始化
}

// 測試
print("--- 非 Lazy ---")
let o1 = Ostrich()        // 這裡會卡 2 秒
print("Ostrich 創建完成")  // 2 秒後才打印

print("\n--- Lazy ---")
let o2 = LazyOstrich()    // 瞬間完成
print("LazyOstrich 創建完成")
print("訪問 bird 屬性...")
_ = o2.bird               // 這裡卡 2 秒
print("Bird 初始化完成")

輸出對比:

--- 非 Lazy ---
🐣 Bird 鳥類 初始化
(等待 2 秒...)
Ostrich 創建完成

--- Lazy ---
LazyOstrich 創建完成
訪問 bird 屬性...
🐣 Bird 鳥類 初始化
(等待 2 秒...)
Bird 初始化完成

四、注意事項與最佳實踐

  1. 結構體也可用 lazy,但構造體方法中修改 lazy 屬性需標記 mutating。
  2. 避免循環引用:閉包中捕獲 self 時使用 [weak self] 或 [unowned self]。
  3. 非線程安全:高併發場景考慮 lazy var resource: Resource = { ... }() 配合 NSLock 或改用 let resource = { ... }() 在構造器中初始化。
  4. 不可觀測初始化過程:無法在初始化前後插入副作用(如日誌、通知),需在閉包內處理。

五、進階:lazy vs 計算屬性

特性lazy 存儲屬性計算屬性
存儲開銷首次訪問後佔用內存不佔用額外內存
計算頻率僅首次計算,後續直接讀取每次訪問皆計算
適用場景昂貴、固定、可緩存的結果輕量、動態、依賴外部狀態

總結

lazy 是 Swift 為「按需初始化」提供的原生語法支持,能顯著優化啟動性能與內存佔用。實戰中,凡涉及耗時構造、非必需即用、依賴 self 上下文的屬性,優先考慮 lazy。但記住:它不是銀彈,線程安全與循環引用仍需開發者把控。


下一期將深入講解計算屬性與屬性觀察器,構建響應式數據流的基石,敬請關注。

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