阅读 2

Swift Tips 018 - Using self-executing closures for lazy properties

代码截图

代码出处: Swift Tips 018 by John Sundell

小笔记

这段代码在说什么

代码截图里的核心点是在于 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 属性的方式,你觉得如何?