2015-01-11 54 views
33

我想在Swift中为我的一些属性使用Lazy初始化。 我当前的代码如下所示:Lazy Var vs Let

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,并忘记财产的不变性质?

+2

我同意 - Swift需要懒惰让。懒惰var模式的另一个问题(当值肯定不会改变时)是,第一次简单读取属性会计算对象的变异(在内部它会进行变异 - 将延迟值存储),但这意味着外部代码必须将对象声明为var,即使从外部代码的角度来看,对象也不会改变。 –

+1

你可以得到的唯一'懒惰'是'var'(从Swift 2.1开始),如果它只是一个浮动任务,我不会担心懒惰,特别是如果你绝对知道它将被访问 – bshirley

回答

20

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

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

这使得像模式:

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

use(x) 

其以前需要使用一个变种,即使没有 突变发生。 (16181314)

很明显,你并不是唯一受挫的人。

+0

@iGodric - 我想我误解了文档中的陈述。我会删除我的评论。 – rghome

+0

这是如何禁止懒惰加载一次? –

16

斯威夫特书has the following note

你必须始终声明一个懒惰的财产(以var关键字)的变量,因为它的初始值可能不是直到实例的初始化完成后进行检索。在初始化完成之前,常量属性必须始终有一个值,因此不能声明为惰性。

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

至于两个选择,你提出去,我会在它们之间基于效率的决定:

  • 如果访问属性的值是很少做的,它是昂贵的计算前期,我将使用var lazy
  • 如果该值的情况下超过20..30%访问,或者是相对便宜的计算,我会用let

注:我将进一步优化你的代码推conditi Onal地区为CGFloat初始化:

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

不需要“返回“和”()“? – YogevSitton

+0

@godmoney是的。一旦'if'语句被一个条件表达式替代,就可以删除它周围很多需要使用语句的语法。当然,如果你的初始化器更复杂 - 比方说,当它使用循环时,你将不得不回到你的语法。 – dasblinkenlight

+0

非常感谢你 – YogevSitton

6

正如dasblinkenlight指出的,懒惰属性应该总是在Swift中声明为变量。但是,可以使该属性为只读,以便只能在实体定义的源文件中进行变异。这是我可以最接近定义“懒惰”的。

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

它提到,你不能'让'周围类型的变量。 – Raphael