更多内容欢迎关注公众号:Swift花园
根据维基百科的定义:
在计算机编程中,懒加载是一种在创建对象,或者计算某个值,或者其他某些开销昂贵的处理过程中延迟执行的策略。这些过程只在第一次被需要的时候才会真正执行。
这个解释差不多总结了懒加载的一切。不过,由于我们是在使用Swift语言,它有一种叫可选型的东西。如果你还没不知道可选型是什么东西,建议先阅读一下我的另一篇文章 :
[极速Swift教程之十] 可选型 ,然后回来我们继续。 🤐
懒人的终极指南
当一个属性只有在某些时刻才被需要,你可以用 lazy 关键字放在它前头。这样它就被排除出初始化过程。它的默认值一经请求,就会赋值。这个特性对于创建开销昂贵或者创建过程耗时的类型很有用。下面是一个睡美人的传说。👸💤
class SleepingBeauty {
init() {
print("zzz...沉睡中...")
sleep(2)
print("睡美人准备好了!")
}
}
class Castle {
var princess = SleepingBeauty()
init() {
print("城堡准备好了!")
}
}
print("一座新的城堡即将出现...")
let castle = Castle()这段代码的输入如下,你可以看到公主睡了很久,还导致城堡被阻塞。🏰
一座新的城堡即将出现...
zzz...沉睡中...
睡美人准备好了!
城堡准备好了!现在,让我们通过添加 lazy 关键字来把事情提速吧,以便我们的英雄有时间去屠龙,同时我们的继续沉睡,直到剧情需要她醒来 🐉 🗡 🤴
class SleepingBeauty {
init() {
print("zzz...沉睡中...")
sleep(2)
print("睡美人准备好了!")
}
}
class Castle {
lazy var princess = SleepingBeauty()
init() {
print("城堡准备好了!")
}
}
print("一座新的城堡即将出现...")
let castle = Castle()
castle.princess这下好多了!城堡会被立即创建,以便战斗立即开始,打败恶龙后王子唤醒公主。他们幸福地生活在一起,happy ending。 👸 ❤️ 🤴
一座新的城堡即将出现...
城堡准备好了!
zzz...沉睡中...
睡美人准备好了!希望你喜欢这个童话故事,现在让我们来点真正的编程。🤓
用懒加载来避免可选型
如你在前面的例子中看到的,懒加载属性可以用于提升代码性能。你还可以用它来抹除对象中的可选型。当你在处理 UIView 的派生类时这会很有用。举个例子,如果你的视图层级需要用到一个UILabel,通常你会需要声明这个视图的可选型属性或者隐式解包可选型属性。这种情况下,我们就可以利用 lazy 关键字消灭邪恶的可选型需求。😈
class ViewController: UIViewController {
lazy var label: UILabel = UILabel(frame: .zero)
override func loadView() {
super.loadView()
self.view.addSubview(self.label)
}
override func viewDidLoad() {
super.viewDidLoad()
self.label.textColor = .black
self.label.font = UIFont.systemFont(ofSize: 16, weight: .bold)
}
}看起来不赖吧。不过,有些人可能还是更习惯于把视图声明为隐式解包可选型。毕竟,旧习难改。💀
使用懒加载闭包
你可以使用懒加载闭包来包装一些代码。基于存储属性做懒加载的主要好处是你的语句块只有那个属性发生读取操作时才会执行。看一下实践代码:
class ViewController: UIViewController {
lazy var label: UILabel = {
let label = UILabel(frame: .zero)
label.translatesAutoresizingMaskIntoConstraints = false
label.textColor = .black
label.font = UIFont.systemFont(ofSize: 16, weight: .bold)
return label
}()
}当你想要整理 init 方法时,这是一种很不错的实践。你可以把所有的定制逻辑放进闭包,在相应的对象被读取时自动执行。在上面的代码中,当self.label 被读取时,定制语句块执行。瞧,你的视图这就准备好了。
注意:虽然你不能在存储属性上直接使用 self,你可以在懒加载方式下用。千万要小心的是,如果你的懒加载对象本身是一个闭包,总是使用 [unowned self],以避免循环引用和内存泄漏。 ♻️
使用工厂进行懒加载初始化
下面我将教你如何把静态方法和静态工厂应用于懒加载属性。
工厂方法
如果你不喜欢上面那种闭包,你还可以把你的代码放进工厂方法,再通过懒加载变量来使用。就像下面这样:
class ViewController: UIViewController {
lazy var label: UILabel = self.createCustomLabel()
private func createCustomLabel() -> UILabel {
print("被调用")
let label = UILabel(frame: .zero)
label.translatesAutoresizingMaskIntoConstraints = false
label.textColor = .black
label.font = UIFont.systemFont(ofSize: 16, weight: .bold)
return label
}
}这里的工厂方法看起来就懒加载属性的私有构造器,还有进一步提升可复用性的空间。
静态工厂
如果你希望在应用的多个部分复用代码,那么把懒加载构造器的代码外包给静态工厂会是一种好的实践。举个例子,自定义 view 的初始化过程就很适合采用这个方式。况且,严格说来创建自定义视图不应该是 view controller 的任务,在这个例子中责任可以分担出去。
class ViewController: UIViewController {
lazy var label: UILabel = UILabel.createCustomLabel()
}
extension UILabel {
static func createCustomLabel() -> UILabel {
let label = UILabel(frame: .zero)
label.translatesAutoresizingMaskIntoConstraints = false
label.textColor = .black
label.font = UIFont.systemFont(ofSize: 16, weight: .bold)
return label
}
}使用静态工厂属性或者方法你还能额外收获一些好处,比如实现缓存或者返回特定的子类型。👍
总结
用懒加载变量来优化代码十分方便,但它们只能用于结构体和类,也不能用于计算属性。
还有一点十分重要,懒加载属性是非线程安全的,所以要小心使用。有的时候,用它来消除隐式解包可选型并非总是好主意,该崩溃的代码还是会崩溃。🐛
懒加载而不是懒。
在能用懒加载的时候尽量用吧! 😉
我的公众号 这里有Swift及计算机编程的相关文章,以及优秀国外文章翻译,欢迎关注~
