Swift 属性声明:类初始化或首个执行块中lazy var与let的使用区别
lazy var 与 let 声明属性在指定开发场景下的核心区别
结合给出的两个示例,两者在初始化时机、内存开销、生命周期适配、可变性约束上的差异非常明确:
- 属性初始化触发时机完全不同
let修饰的存储属性,会在实例创建完成的阶段(也就是UIViewController的init流程执行结束时)就立刻完成初始化。哪怕整个控制器生命周期里你从来没访问过这个label,对应的UILabel实例在控制器刚被创建时就已经生成。lazy var修饰的属性,只有第一次被代码访问时才会真正执行初始化逻辑,且初始化逻辑只会执行一次。对应你的示例,UILabel()的创建代码只有走到viewDidLoad里的label.text = "hey"这行、第一次触达属性访问时才会执行,之后的访问和普通的可变属性没有差异。 - UIKit 生命周期的适配性差异
控制器的init阶段和后续的viewDidLoad阶段是完全独立的两个流程:init执行时控制器的根视图还没被加载,屏幕尺寸、安全区、导航栏状态这些视图相关的信息都还没确定。
用let在控制器初始化阶段就创建视图类控件,本质就是生成了一个完全脱离当前视图流程的离屏对象,不仅没法拿到正确的布局上下文,还可能触发系统隐式的视图布局逻辑带来不必要的性能损耗。
而lazy var把初始化时机推迟到第一次访问(也就是你在viewDidLoad里使用属性的节点),刚好匹配视图加载完成后的流程节奏,完全符合 UIKit 的生命周期设计逻辑。 - 内存占用的差异
只要控制器实例存在,let声明的属性就会一直占用对应的内存——哪怕这个属性从来没被使用过、也没被加到视图层级里。
如果代码从头到尾没有访问过这个lazy var属性,它的初始化逻辑永远不会执行,对应的内存也永远不会被分配,能避免大量无效的内存开销。 - 可变性约束的差异
let修饰的属性,仅仅是引用地址不可变:你不能把label重新指向另一个新的UILabel实例,但label自身的属性(比如text、frame)完全可以正常修改。lazy var因为是var修饰的,不仅可以修改属性内部的值,还可以随时把整个label引用替换为其他实例,灵活性更高,但对引用的不可变约束更弱。
补充一个常见误区:很多开发者会误以为
let声明控件更早初始化会更可靠,实际在 iOS 控制器的开发场景中,过早在init阶段初始化视图控件,往往是无意义的性能浪费,也是很多隐蔽的内存泄漏问题的来源。
内容的提问来源于stack exchange,提问作者Mellao
相关产品推荐
相关产品推荐

