迅速-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而不考虑物业的固定性质?

YogevSitton asked 2020-06-27T10:51:01Z
4个解决方案
25 votes

这是Xcode 6.3 Beta / Swift 1.2发行说明中的最新经文:

让常量被广义化为不再需要立即数 初始化。 新规则是必须让let常数为 在使用前初始化(例如var),并且只能 已初始化:初始化后未重新分配或更改。

这样可以启用以下模式:

let x: SomeThing
if condition {
    x = foo()
} else {
    x = bar()
}

use(x)

它以前需要使用var,即使没有 发生突变。 (16181314)

显然,您不是唯一对此感到沮丧的人。

Chris Conover answered 2020-06-27T10:51:33Z
22 votes

Swift书有以下注释:

您必须始终将惰性属性声明为变量(使用var关键字),因为直到实例初始化完成后才能检索其初始值。 常量属性在初始化完成之前必须始终具有一个值,因此不能声明为惰性。

这在实现该语言的上下文中是有道理的,因为所有常量存储的属性都是在对象初始化完成之前计算的。 这并不意味着将CGFloatlazy一起使用时可能会更改其语义,但是尚未完成,因此此时var仍然是lazy的唯一选择。

至于您提出的两个选择,我将根据效率在它们之间做出决定:

  • 如果很少访问属性值,并且前期计算成本很高,我将使用CGFloat
  • 如果在超过20..30%的情况下访问该值,或者计算起来相对便宜,我将使用CGFloat

注意:我将进一步优化您的代码以将条件推送到CGFloat初始化程序中:

let fontSize : CGFloat = CGFloat(someCase  ? 30 : 17)
dasblinkenlight answered 2020-06-27T10:52:22Z
10 votes

正如dasblinkenlight指出的那样,应始终将惰性属性声明为Swift中的变量。 但是,可以将属性设置为只读,以便只能从定义实体的源文件中对其进行更改。这是我定义“懒惰的let”所能获得的最接近的结果。

private(set) lazy var fontSize: CGFloat = {
    if someCase {
        return 30
    } else {
        return 17
    }
}()
sdduursma answered 2020-06-27T10:52:42Z
0 votes

您可以将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导致编译错误。

Roman Podymov answered 2020-06-27T10:53:15Z
translate from https://stackoverflow.com:/questions/27886024/lazy-var-vs-let