Lazy Var vs Let

时间:2015-01-11 10:24:51

标签: swift var lazy-initialization let

我想对Swift中的一些属性使用Lazy初始化。 我目前的代码如下:

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并忘记懒惰的初始化?或者我应该使用lazy var并忘记属性的恒定性质?

4 个答案:

答案 0 :(得分:24)

这是Xcode 6.3 Beta / Swift 1.2 release notes的最新经文:

  

让常量推广到不再需要立即   初始化。新规则是必须使用常量   在使用之前初始化(如var),并且它可能只是   初始化:初始化后未重新分配或变异。

     

这样可以实现以下模式:

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

use(x)
  

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

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

答案 1 :(得分:22)

Swift book has the following note

  

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

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

就你提出的两个选择而言,我会根据效率来决定:

  • 如果很少访问属性的值,并且预先计算成本很高,我会使用var lazy
  • 如果超过20..30%的情况下访问该值或计算成本相对较低,我会使用let

注意:我会进一步优化您的代码,将条件推送到CGFloat初始值设定项:

let fontSize : CGFloat = CGFloat(someCase  ? 30 : 17)

答案 2 :(得分:10)

正如dasblinkenlight指出的那样,懒惰属性应始终在Swift中声明为变量。但是,有可能将属性设置为只读,因此它只能从定义实体的源文件中进行变换。这是我可以定义“懒惰”的最接近的。

private(set) lazy var fontSize: CGFloat = {
    if someCase {
        return 30
    } else {
        return 17
    }
}()

答案 3 :(得分:0)

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