Swift 中的 lazy 属性是什么?如何使用 lazy 属性?lazy 属性的初始化时机是什么?
Swift 中的 lazy 属性是一种延迟初始化机制,只有在第一次访问时才会计算其初始值。这对于初始化成本较高或依赖其他属性的场景非常有用。
lazy 属性的特点:
- 使用
lazy关键字声明 - 必须是变量(var),不能是常量(let)
- 必须有初始值或闭包初始化
- 第一次访问时才进行初始化
- 初始化后保持值不变(除非被重新赋值)
- 线程不安全,多线程环境下需要注意
基本用法:
swiftclass DataImporter { var filename = "data.txt" } class DataManager { lazy var importer = DataImporter() var data = [String]() } let manager = DataManager() manager.data.append("Some data") // 此时 importer 还没有被初始化 print(manager.importer.filename) // 第一次访问 importer 时才进行初始化
使用闭包初始化:
swiftclass ImageLoader { lazy var image: UIImage = { let url = URL(string: "https://example.com/image.jpg")! let data = try! Data(contentsOf: url) return UIImage(data: data)! }() lazy var cachedImage: UIImage = { print("Loading image...") return UIImage(named: "cached")! }() }
lazy 属性的初始化时机:
- 第一次访问属性时
- 不是在类实例化时
- 即使访问失败,也会尝试初始化
- 示例:
swift
class LazyExample { lazy var expensiveValue: Int = { print("Calculating expensive value...") return Int.random(in: 1...1000) }() } let example = LazyExample() print("Instance created") // 输出: Instance created print(example.expensiveValue) // 输出: Calculating expensive value... // 输出: (随机数) print(example.expensiveValue) // 输出: (相同的随机数,不会重新计算)
lazy 属性的应用场景:
-
初始化成本高的对象:
swiftclass DatabaseManager { lazy var connection: DatabaseConnection = { let conn = DatabaseConnection() conn.connect() return conn }() } -
依赖其他属性的对象:
swiftclass ViewController { var userID: String? lazy var userProfile: UserProfile = { guard let id = userID else { return UserProfile.guest } return UserProfile.load(id: id) }() } -
单例模式:
swiftclass Singleton { static let shared = Singleton() lazy var expensiveResource: Resource = { return Resource() }() }
注意事项:
- lazy 属性不是线程安全的
- 不能在结构体中使用 lazy 属性(因为结构体是值类型)
- lazy 属性不能是常量
- 如果初始化闭包抛出错误,需要处理错误
- 在多线程环境下,可能需要添加同步机制
最佳实践:
- 用于初始化成本高的属性
- 用于依赖其他属性的属性
- 用于可能不会被使用的属性
- 注意线程安全问题
- 避免在 lazy 属性中使用 self 产生循环引用