迅速-Lazy Var vs L
我想对Swift的某些属性使用惰性初始化。我当前的代码如下所示:
lazy var fontSize : CGFloat = {
if (someCase) {
return CGFloat(30)
} else {
return CGFloat(17)
}
}()
事实是,一旦设置fontSize,它就永远不会改变。所以我想做这样的事情:
lazy let fontSize : CGFloat = {
if (someCase) {
return CGFloat(30)
} else {
return CGFloat(17)
}
}()
这是不可能的。
仅此有效:
let fontSize : CGFloat = {
if (someCase) {
return CGFloat(30)
} else {
return CGFloat(17)
}
}()
所以-我想要一个可以延迟加载但永远不会改变的属性。正确的方法是什么? 使用let
并忘记了懒惰的init? 还是我应该使用lazy var
而不考虑物业的固定性质?
这是Xcode 6.3 Beta / Swift 1.2发行说明中的最新经文:
让常量被广义化为不再需要立即数 初始化。 新规则是必须让let常数为 在使用前初始化(例如var),并且只能 已初始化:初始化后未重新分配或更改。
这样可以启用以下模式:
let x: SomeThing
if condition {
x = foo()
} else {
x = bar()
}
use(x)
它以前需要使用var,即使没有 发生突变。 (16181314)
显然,您不是唯一对此感到沮丧的人。
Swift书有以下注释:
您必须始终将惰性属性声明为变量(使用var关键字),因为直到实例初始化完成后才能检索其初始值。 常量属性在初始化完成之前必须始终具有一个值,因此不能声明为惰性。
这在实现该语言的上下文中是有道理的,因为所有常量存储的属性都是在对象初始化完成之前计算的。 这并不意味着将CGFloat
与lazy
一起使用时可能会更改其语义,但是尚未完成,因此此时var
仍然是lazy
的唯一选择。
至于您提出的两个选择,我将根据效率在它们之间做出决定:
- 如果很少访问属性值,并且前期计算成本很高,我将使用
CGFloat
- 如果在超过20..30%的情况下访问该值,或者计算起来相对便宜,我将使用
CGFloat
注意:我将进一步优化您的代码以将条件推送到CGFloat
初始化程序中:
let fontSize : CGFloat = CGFloat(someCase ? 30 : 17)
正如dasblinkenlight指出的那样,应始终将惰性属性声明为Swift中的变量。 但是,可以将属性设置为只读,以便只能从定义实体的源文件中对其进行更改。这是我定义“懒惰的let”所能获得的最接近的结果。
private(set) lazy var fontSize: CGFloat = {
if someCase {
return 30
} else {
return 17
}
}()
您可以将Burritos用于延迟常量属性。 该库为Swift 5.1提供了不同的属性包装器。 通过将以下行添加到Podfile中,将其与CocoaPods一起安装:
pod 'Burritos'
使用此库,您可以替换
lazy var fontSize : CGFloat = {
if (someCase) {
return CGFloat(30)
} else {
return CGFloat(17)
}
}()
与
@LazyConstant var fontSize : CGFloat = {
if (someCase) {
return CGFloat(30)
} else {
return CGFloat(17)
}
}()
然后self.fontSize = 20
导致编译错误。