计算属性和使用闭包设置的属性之间的区别

86

我对Swift还不熟悉。计算属性和设置为闭包的属性有什么区别?我知道计算属性每次都会重新计算,闭包是否也是如此呢?

闭包:

var pushBehavior: UIPushBehavior = {
    let lazilyCreatedPush = UIPushBehavior()
    lazilyCreatedPush.setAngle(50, magnitude: 50)
    return lazilyCreatedPush
}()

计算:

var pushBehavior: UIPushBehavior {
    get{
        let lazilyCreatedPush = UIPushBehavior()
        lazilyCreatedPush.setAngle(50, magnitude: 50)
        return lazilyCreatedPush
    }
}
4个回答

144

简而言之,第一个是存储属性,通过闭包初始化,当它被初始化时,该闭包仅调用一次。第二个是计算属性,每次引用该属性时都会调用get块。


存储属性的初始化闭包仅在初始化时调用一次,但您可以稍后更改存储属性的值(除非将var替换为let)。当您想要将代码封装到单个简洁的代码块中以初始化存储属性时,这很有用。

然而,每次引用计算属性时都会调用其块。当您希望每次引用计算属性时都调用代码时,这很有用。通常情况下,当计算属性需要每次引用存储属性时重新计算(例如从其他可能是私有的存储属性重新计算)时,会这样做。

在这种情况下,毫无疑问,您需要存储属性(第一个示例),而不是计算属性(第二个示例)。您可能不希望每次引用变量时都创建一个新的推入行为对象。


顺便说一下,在您的第一个示例中,您内部引用它被惰性实例化。如果您想要该行为,则必须使用lazy关键字:

lazy var pushBehavior: UIPushBehavior = {
    let behavior = UIPushBehavior()
    behavior.setAngle(50, magnitude: 50)
    return behavior
}()

然而,如果属性是 static,它会自动地惰性实例化。


5
非常棒的解释...!! ;) - itsji10dra

9

Closure :

  //closure
    var pushBehavior: UIPushBehavior = {
        let lazilyCreatedPush = UIPushBehavior()
        lazilyCreatedPush.setAngle(50, magnitude: 50)
        return lazilyCreatedPush
    }()

当第一次调用pushBehavior变量时,代码块会执行并将值保存在pushBehavior变量中。之后,每当您调用pushBehavior时,这些值都会被返回。

这意味着只有第一次执行代码块并将其保存在此变量中。

另外,您可以在需要的时候存储变量值,但之后这些值会被返回,但如果您将其声明为“let”,则无法更改此值。

计算属性:

var pushBehavior: UIPushBehavior {
    get{
        let lazilyCreatedPush = UIPushBehavior()
        lazilyCreatedPush.setAngle(50, magnitude: 50)
        return lazilyCreatedPush
    }
}

在计算属性中,每当您调用pushBehavior变量时,此代码块就会执行并返回值。因此,每次都会执行此代码块。 并且您不能将pushBehavior变量声明为“let”关键字。
所以,您可以根据您的要求使用此代码。

闭包将立即被初始化,无论您是否使用它。它不会进行懒加载。顺便说一句,在句点后将第一个单词大写,阅读会更加愉悦。 - Kent Liau

5
主要的区别在于计算属性没有setter,因此无法对其进行赋值。在这种情况下,闭包只被调用一次,返回值被存储在变量中,因此如果结果随时间不变,则使用存储变量比计算属性更有效率。
总的来说,只有当可以快速检索值时才应使用计算属性。
附注:如果您不更改/重新分配存储的变量,则应考虑将其定义为常量(let)。

4

虽然这不是一个答案,但值得一提的是:

  • 存储属性的值必须在初始化完成后才能知道。这可以通过默认值或初始化来实现。
  • 计算属性的值直到被访问时才会计算
  • 懒加载属性的值在被访问之前未定义

因此,对于计算属性和懒加载变量,您可以毫无顾虑地访问self或存储属性。


对于惰性变量:"在访问之前未定义" 可以重写为 "在访问之前未计算",但我觉得 "define" 和 "compute" 之间有微妙的意义差异... - mfaani

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接