Swift 懒性属性
及时求值与懒性求值
及早求值:尽可能早的计算表达式的值,以便在使用时直接使用。
懒性求值(Lazy evaluation):将代码中求值延迟到需要结果值时再进行。
在一般的开发中,苹果希望我们以及早求值的方式进行编程,但是懒性加载可以提高性能和便利性,我们可以适当添加懒性求值。
懒加载应用
Objective-C 中的懒加载
OC中是通过判断是否含有值,如果有就直接返回值,没有就创建对象返回。
// ClassA.h
@property (nonatomic, copy) NSString *testString;
// ClassA.m
- (NSString *)testString {
if (!_testString) {
_testString = @"Hello";
NSLog(@"只在首次访问输出");
}
return _testString;
}
Swift中的懒加载
在 Swift 中我们可以通过 lazy
属性修饰符来指定属性为懒加载属性。
示例:
class ClassA {
lazy var str: String = {
let str = "Hello"
print("只在首次访问输出")
return str
}()
}
简单的懒加载可以这样写
lazy var str: String = "Hello Lazy"
Swift 标准库的 lazy 方法
在标准库中,常用基本类型(字典、字符串、数组)具有一个 lazy 属性,可以获取来进行懒性求值的操作(比如 map、filter等)
比如进行数组 map 操作
及早求值
let data = 1...3
let result = data.map {
(i: Int) -> Int in
print("正在处理 \(i)")
return i * 2
}// result 在此时就会使用资源计算出来。
print("准备访问结果")
for i in result {
print("操作后结果为 \(i)")
}
print("操作完毕")
输出:
// 正在处理 1
// 正在处理 2
// 正在处理 3
// 准备访问结果
// 操作后结果为 2
// 操作后结果为 4
// 操作后结果为 6
// 操作完毕
懒性求值
let data = 1...3
let result = data.lazy.map { // 先进行一次 lazy 操作
(i: Int) -> Int in
print("正在处理 \(i)")
return i * 2
} // 懒操作,不做计算处理。
print("准备访问结果")
for i in result { // 访问的时候再处理,而且是操作哪个再处理哪个。
print("操作后结果为 \(i)")
}
print("操作完毕")
输出:
// 准备访问结果
// 正在处理 1
// 操作后结果为 2
// 正在处理 2
// 操作后结果为 4
// 正在处理 3
// 操作后结果为 6
// 操作完毕
可以看到,懒性求值在需要的时候才进行值操作。
应用场景
- 可能存在大量资源占用,可以把部分属性声明为 lazy, 比如 ViewController 声明,就存在页面初始化需要加载 xib 和初始化化各种属性。此时部分属性就可以用 lazy 进行懒性求值,以缓解性能。
- 数据量大,比如大容量数组进行 map , filter 操作时,可以先获取 lazy 容器,以便用到才计算参考
- 对外暴露的属性,也可通过 lazy 懒操作,以便外部使用时候才计算。不用一开始初始化就进行大量计算和占用资源参考。
- 声明需要使用才计算的属性参考。
更多懒操作可以查看官网文档LazySequence
注意
进行 lazy 属性声明时候,如果使用 self
请使用[unowned self]
或者 [weak self]
来避免循环引用。
Lazy 属性不是线程安全的。
参考
Swift lazy 修饰符和方法 – 王巍
懒性求值 – IBM
Swift 标准库的条件符合性 – Swift 官方文档关于Lazy的介绍
什么是惰性变量 – hackingWithSwift 告诉你可以通过懒性计算来避免昂贵的计算操作。