Swift Tips 018 - Using self-executing closures for lazy properties
每天了解一点不一样的 Swift 小知识
代码截图
小笔记
这段代码在说什么
代码截图里的核心点是在于 StoreViewController 里的 collectionView 属性不仅是一个延时加载存储属性,还采用了闭包的方式初始化属性缺省值。
lazy 关键字
延时加载属性是指当第一次被调用的时候才会计算其初始值的属性。在属性声明前使用 lazy 来标识一个延时加载属性。
必须将延时加载属性声明成变量(使用 var 关键字),因为属性的初始值可能在实例构造完成之后才会得到。而常量属性在构造过程完成之前必须要有初始值,因此无法声明成延时加载。
用闭包的方式初始化属性缺省值
和其他属性一样,我们可以用自执行(self-executing)闭包来给 lazy 变量设定默认值,也就是用 = { /* some code */ }()
的方式替换掉 = some code
的方式。
需要注意的一点是,当属性是 lazy 时, 这意味着它的初始值暂时不会被计算,当需要计算的时候,self
已经完成初始化。这就是为什么你可以在那里使用 self ,这和非 lazy 属性正好相反:它的初始值在初始化阶段就被计算出来了。
这样做的好处
在说好处之前,我们先将代码还原成不用 lazy 关键字和自执行闭包的状态。你的代码大体可能如下:
class StoreViewController: UIViewController {
private var collectionView: UICollectionView?
override func viewDidLoad() {
super.viewDidLoad()
let layout = UICollectionViewFlowLayout()
self.collectionView = UICollectionView(frame: self.view.bounds, collectionViewLayout: layout)
self.collectionView.delegate = self
self.collectionView.dataSource = self
if let subView = self.collectionView {
view.addSubview(subView)
}
}
}
相比于原先的代码,viewDidLoad 里面的核心逻辑是向 view 里添加 子视图。但现在的这份代码在 viewDidLoad 整合了 collectionView 的初始化代码,除了代码结构上变得有些不那么整洁外,我们也可能无法保证 collectionView 只被初始化一次了。
所以用自执行闭包初始化 lazy 属性的方式,你觉得如何?