Lazy Property 是 Swift 中的一种延迟初始化机制,属性在首次访问时计算,而不是在创建对象时。与普通的 stored properties 不同,懒变量可以显著减少资源密集型操作的启动时间和内存消耗。根据 Apple Developer Documentation (2026) 的说明,懒属性保证只初始化一次,并且在首次访问时是线程安全的。
要点
Lazy Property 是一种 stored property,其初始化延迟到首次访问。关键字 lazy 放在 var 声明之前,告诉编译器不要在创建对象时计算值。
在标准情况下,所有 stored properties 在创建类或结构的实例时初始化。如果属性需要复杂计算、网络加载或与文件系统交互,lazy 允许将操作延迟到真正需要数据时。
根据 Swift by Sundell (2025) 的观点,懒属性是 iOS 应用程序中最有效的性能优化工具之一。它们允许在具有繁重初始设置的应用程序(如图形编辑器或分析仪表板)中减少 20-40% 的启动时间。
声明懒属性需要在 var 前加上关键字 lazy。值通过闭包或函数调用来设置。
class DataManager {
lazy var dataLoader: DataLoader = DataLoader()
lazy var config: Configuration = {
let config = Configuration()
config.loadDefaults()
return config
}()
}
懒属性的闭包只计算一次,并在后续访问时返回存储的值。这对于多步骤的复杂配置特别方便。
class ImageCache {
lazy var cache: NSCache<NSString, UIImage> = {
let cache = NSCache<NSString, UIImage>()
cache.countLimit = 100
cache.totalCostLimit = 50 * 1024 * 1024
return cache
}()
}
多个懒属性彼此独立初始化。如果两个懒属性通过闭包相互引用——会产生 Swift 无法自动解决的循环依赖。
初始化的时机是 lazy 与普通 stored properties 的关键区别。初始化发生在属性的第一次读取或写入时,但不会更早。
初始化在首次访问属性时触发,无论是读取还是写入。在此之前,不会为属性分配内存——只存储一个「未初始化」的标志。
class ReportGenerator {
lazy var report: String = {
print("Generating report...")
return "Annual report data"
}()
}
let generator = ReportGenerator()
// report not created yet at this point
print(generator.report) // "Generating report..."
print(generator.report) // not regenerated on subsequent access
懒属性不能在子类中被重写。如果一个类声明了一个懒属性,子类不能将其重写为具有不同行为的 computed 或 stored property。
根据 Apple Swift Blog (2025) 的说明,这个限制是因为 lazy 不是重写修饰符,而是存储的实现细节。子类只能重写懒属性在闭包中调用的方法。
懒属性的初始化在 Swift 中是线程安全的:如果两个线程同时访问一个懒属性,初始化只执行一次,第二个线程会被阻塞直到完成。
然而,初始化后同步会被移除。这意味着多个线程同时读取是安全的,但如果一个线程向 lazy var 写入新值而另一个线程读取——就会发生 data race。
根据 Swift Evolution proposal SE-0254 (2025) 的说明,懒属性的同步机制是通过底层的 objc_sync_enter/exit 实现的。这保证了初始化的原子性,但不保证后续的修改。为了安全地使用可变的懒属性,请使用单独的同步机制。
懒属性在 Swift 项目中用于优化性能和改进代码架构。
加载图像、解析 JSON、与数据库交互——所有这些操作都可以使用 lazy 延迟到用户真正需要数据时。
class ProfileViewController {
lazy var avatarImageView: UIImageView = {
let imageView = UIImageView()
imageView.contentMode = .scaleAspectFill
imageView.clipsToBounds = true
return imageView
}()
}
服务和管理器如果在应用程序启动时不需要立即使用,可以有效地声明为 lazy。这减少了启动时间和内存消耗。
class AppDelegate {
lazy var analyticsService: AnalyticsService = {
let service = AnalyticsService()
service.configure()
return service
}()
lazy var notificationManager: NotificationManager = {
NotificationManager()
}()
}
在以编程方式创建界面时(不使用 Storyboard),懒属性可以在不使 init 变得臃肿的情况下组织 UI 元素的初始化。
第一个限制:lazy 不能与 let 一起使用。常量必须在 init 完成之前初始化,这与延迟初始化的理念相矛盾。
第二个限制:lazy 不适用于 computed properties。Computed properties 不存储值,而 lazy 正是具有延迟初始化的 stored property。
第三个限制:结构体中的懒属性可能导致可变性问题。如果带有懒属性的结构体被声明为 let,则无法访问该属性,因为初始化需要对结构体进行修改。
第四个:懒属性在初始化时不会触发 willSet/didSet。只有在后续更改时才会触发,如果属性被声明为 var。
根据 Stack Overflow (2025) 的数据,大约 15% 关于 lazy 的问题涉及在 let 上下文中使用 lazy 或不理解初始化的一次性特性。在设计类时,这些限制需要重要考虑。
常见问题
不可以,lazy 仅适用于 var。let 常量必须在 init 完成之前初始化,这与延迟初始化不兼容。
恰好一次。在首次访问时属性被初始化,之后返回存储的值而不再重新计算。
初始化是线程安全的——两个线程不会两次初始化该属性。然而,后续的修改不会自动同步。
不可以,懒属性不能被重写。子类只能改变闭包内的逻辑,但无法改变懒初始化本身。
Lazy 是只计算一次并存储值的 stored property。Computed property 在每次访问时计算且不存储值。
总结
我们将开发一款交钥匙移动应用程序
IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。