5月27日 11:52

Swift lazy 属性是什么?初始化时机和线程安全怎么处理?

lazy 延迟初始化——属性第一次被访问时才计算初始值,之后缓存结果。声明方式:lazy var importer = DataImporter()lazy var config: Config = { loadConfig() }()。必须是 var(let 在 init 时就必须有值)。

lazy 的典型场景:初始化成本高的对象(数据库连接、大图加载)、依赖其他属性后才能初始化的值、不是每次都会用到的属性(省内存)。

追问

lazy 属性线程安全吗?

不安全。如果两个线程同时首次访问同一个 lazy 属性,它可能被初始化两次,或者一个线程拿到未完全初始化的值。解决方案:用 lazy var + 串行队列保护,或者改用 actor 隔离。如果线程安全是刚需,别用 lazy,用手动初始化 + 锁。

lazy 和计算属性有什么区别?

计算属性每次访问都重新计算,lazy 只计算一次然后缓存。如果计算结果不会变且计算成本高,用 lazy;如果结果依赖可能变化的值,用计算属性。lazy 占用存储空间(缓存结果),计算属性不占。

lazy 闭包里能引用 self 吗?

能。lazy 闭包在实例初始化完成后才执行,此时 self 已经可用,所以不需要 [weak self]。但这也意味着 lazy 闭包会强引用 self——如果 lazy 属性在闭包里引用了 self 的属性/方法,会形成循环引用(self 持有 lazy 属性,lazy 闭包持有 self)。用 [weak self] 可以打破,但要注意解包。

lazy 能和 didSet 一起用吗?

不能。lazy 属性不能有属性观察器——因为 lazy 的初始化时机不确定,观察器的触发时机也变得模糊。如果需要在 lazy 初始化后执行副作用,在 lazy 闭包里手动调用。

写段代码

swift
class DataManager { lazy var importer = DataImporter() // 第一次访问才创建 lazy var config: Config = { print("Loading config...") return loadConfig() }() var data: [String] = [] } let manager = DataManager() manager.data.append("item") // importer 还没创建 print(manager.importer) // 此刻才创建 DataImporter // lazy 闭包引用 self(注意循环引用) class ViewController { lazy var label: UILabel = { let lbl = UILabel() lbl.text = self.title // 强引用 self return lbl }() var title: String = "" }
标签:Swift