Swift 的惰性变量
Swift's Lazy Var
阅读 Swift 的 lazy 变量后,我有以下问题:
class MainViewController: UIViewController {
lazy var heavyClass = HeavyClass()
func buttonPressed () {
//Use heavyClass here
self.heavyClass.doStuff()
}
}
所以你使用上面的惰性变量来优化代码,所以 heavyClass 不会立即分配。因此,在启动时,这将是最佳选择,因为 heavyClass 不会在启动时分配。
但是,这不是和上面一样吗?
class MainViewController: UIViewController {
var heavyClass : HeavyClass?
func buttonPressed () {
//Use heavyClass here
self.heavyClass = HeavyClass()
self.heavyClass!.doStuff()
}
}
在您的示例中,结果并不完全相同,表现在以下方面:
单一实例化。每次调用 buttonPressed()
时,都会实例化一个新的 HeavyClass
。使用 lazy 关键字时情况并非如此,它只会在第一次访问时创建实例。为了匹配惰性语义,您必须在每次访问之前检查并设置 if heavyClass == nil
。
可空性。每次要使用它时都必须解包 heavyClass
,可以通过可选链接 (heavyClass?.doStuff()
) 或强制解包 (heavyClass!.doStuff()
)。您还可以将变量设置回 nil
,这在第一个示例中将是编译器错误。
惰性变量的真正优势是当您有多个地方使用该变量时。我相信您可以在这里发现重复:
func buttonPressed() {
if self.heavyClass == nil {
self.heavyClass = HeavyClass()
}
self.heavyClass?.doStuff()
}
func aDifferentButtonPressed() {
if self.heavyClass == nil {
self.heavyClass = HeavyClass()
}
self.heavyClass?.doSomethingElse()
}
这是使用惰性变量整理的:
func buttonPressed() {
self.heavyClass.doStuff()
}
func aDifferentButtonPressed() {
self.heavyClass.doSomethingElse()
}
有多种方法可以解决同一个问题,但我将在这里讨论其中的几种。问题是您只想在需要时分配内存。在某些情况下,您可能会使用一种或另一种方式,而且它可能在某种程度上受到您的编码风格的影响。一方面,假设 class 需要一些设置,因此使用 lazy 可能会提供更好的代码可读性。例如:
lazy var heavyClass: HeavyClass = {
let heavyClass = HeavyClass()
heavyClass.attribute1 = X
heavyClass.attribute2 = X
heavyClass.attribute3 = X
heavyClass.attributeAndSoOn = X
return heavyClass
}()
要点是,所有标准设置都是自包含的,您仍然只有在需要时才能从内存分配中获益。您不必添加功能或延长您的动作例程(例如 buttonPressed)。
在另一种情况下,您可以使用可选值,但这确实增加了值为 nil 的可能性。然后你必须添加逻辑来处理这个。
我也看到了 force-unwrapped 模型,但我自己并没有使用它。它看起来像这样:
class MainViewController: UIViewController {
var heavyClass : HeavyClass!
func buttonPressed () {
//Use heavyClass here
heavyClass = {
let heavyClass = HeavyClass()
// do your other stuff here
return heavyClass
}()
heavyClass.doStuff()
}
}
全凭喜好。我会说惰性变量也不是线程安全的。因此,如果可以有多个线程使用该对象,则一个线程就有可能访问部分构造的对象。
希望对您有所帮助!
阅读 Swift 的 lazy 变量后,我有以下问题:
class MainViewController: UIViewController {
lazy var heavyClass = HeavyClass()
func buttonPressed () {
//Use heavyClass here
self.heavyClass.doStuff()
}
}
所以你使用上面的惰性变量来优化代码,所以 heavyClass 不会立即分配。因此,在启动时,这将是最佳选择,因为 heavyClass 不会在启动时分配。
但是,这不是和上面一样吗?
class MainViewController: UIViewController {
var heavyClass : HeavyClass?
func buttonPressed () {
//Use heavyClass here
self.heavyClass = HeavyClass()
self.heavyClass!.doStuff()
}
}
在您的示例中,结果并不完全相同,表现在以下方面:
单一实例化。每次调用
buttonPressed()
时,都会实例化一个新的HeavyClass
。使用 lazy 关键字时情况并非如此,它只会在第一次访问时创建实例。为了匹配惰性语义,您必须在每次访问之前检查并设置 ifheavyClass == nil
。可空性。每次要使用它时都必须解包
heavyClass
,可以通过可选链接 (heavyClass?.doStuff()
) 或强制解包 (heavyClass!.doStuff()
)。您还可以将变量设置回nil
,这在第一个示例中将是编译器错误。
惰性变量的真正优势是当您有多个地方使用该变量时。我相信您可以在这里发现重复:
func buttonPressed() {
if self.heavyClass == nil {
self.heavyClass = HeavyClass()
}
self.heavyClass?.doStuff()
}
func aDifferentButtonPressed() {
if self.heavyClass == nil {
self.heavyClass = HeavyClass()
}
self.heavyClass?.doSomethingElse()
}
这是使用惰性变量整理的:
func buttonPressed() {
self.heavyClass.doStuff()
}
func aDifferentButtonPressed() {
self.heavyClass.doSomethingElse()
}
有多种方法可以解决同一个问题,但我将在这里讨论其中的几种。问题是您只想在需要时分配内存。在某些情况下,您可能会使用一种或另一种方式,而且它可能在某种程度上受到您的编码风格的影响。一方面,假设 class 需要一些设置,因此使用 lazy 可能会提供更好的代码可读性。例如:
lazy var heavyClass: HeavyClass = {
let heavyClass = HeavyClass()
heavyClass.attribute1 = X
heavyClass.attribute2 = X
heavyClass.attribute3 = X
heavyClass.attributeAndSoOn = X
return heavyClass
}()
要点是,所有标准设置都是自包含的,您仍然只有在需要时才能从内存分配中获益。您不必添加功能或延长您的动作例程(例如 buttonPressed)。
在另一种情况下,您可以使用可选值,但这确实增加了值为 nil 的可能性。然后你必须添加逻辑来处理这个。
我也看到了 force-unwrapped 模型,但我自己并没有使用它。它看起来像这样:
class MainViewController: UIViewController {
var heavyClass : HeavyClass!
func buttonPressed () {
//Use heavyClass here
heavyClass = {
let heavyClass = HeavyClass()
// do your other stuff here
return heavyClass
}()
heavyClass.doStuff()
}
}
全凭喜好。我会说惰性变量也不是线程安全的。因此,如果可以有多个线程使用该对象,则一个线程就有可能访问部分构造的对象。
希望对您有所帮助!