【问题标题】:What makes a property a computed property in Swift是什么让属性成为 Swift 中的计算属性
【发布时间】:2017-02-20 12:27:46
【问题描述】:

让我们从代码sn-p开始:

St Foo {
    var proA: Int = 0 { // needs initialization
        willSet {
            print("about to set proA to \(newValue) from \(proA)")
        }
        didSet {
            print("already set proA to \(proA) from \(oldValue)")
        }
    }

    var ProB: Int { // do not needs initialization 
        return 1
    }
}

let foo = Foo()
foo.proA = 23
print(foo.ProB)

以下是我个人对存储和计算属性的一些理解:

a:只有观察者的属性(willSet 和 didSet)不是计算属性,而是存储属性(例如上面代码中的 proA 属性)。

b:计算属性不能有初始化(见上面代码的cmets)。

c: setter 有点等于属性观察者,属性观察者只是变异前后的 setter + 观察者。

问题:

1. 我想知道是什么让属性成为计算属性?只要属性有一个getter并返回它是一个计算属性,这是否正确?

2. 我的所有理解(a、b 和 c)都正确吗?如果没有,请您指出。

3. 为什么不允许初始化计算属性? (请看下图)当我这样做时,编译器会发出警告 Cannot call value of none-function type "int" 这个错误是什么意思?

非常感谢。

【问题讨论】:

    标签: swift properties computed-properties property-observer


    【解决方案1】:

    首先,这是关于变量,而不是属性任何变量都可以是计算变量。属性只是使用变量的一种方式。

    我认为总体而言,您将存储变量与 setter 观察者并排放置与计算变量是犯了一个大错误。他们是无关的!

    将计算变量想象成在使用时看起来和行为都像变量的东西——你得到并(也许)设置它——但实际上是一个函数(或一对函数)。 这只是调用函数的一种紧凑方式。这就是全部

    另一方面,带有观察者的存储变量只是一个也有一些观察者的存储变量。


    好的,关于你的问题:

    1. 我想知道是什么让属性成为计算属性?只要属性有一个 getter 并返回它就是一个计算属性,这是否正确?

    是的。它是一个计算变量,因为您使用使其成为计算变量的语法声明它(使用花括号)。

    1. 我的所有理解(a、b 和 c)都正确吗?如果不是,请您指出

    是的。我认为您的“c”非常有见地:计算变量不需要设置器 observer 因为它有(喘气!)设置器!

    1. 为什么不允许初始化计算属性? (请看下图)当我这样做时,编译器会发出警告 Cannot call value of none-function type "int" 这个错误是什么意思?

    计算变量“有”值是没有意义的——它是被计算的!这只是一些功能! ——所以给它分配一个“初始”值是没有意义的。

    【讨论】:

    • 是的,关于“b”选项,你是对的,我犯了一个错误,我的意思是“必须没有”。已经修复
    • 感谢您的参考,我现在就阅读。我昨天在亚马逊上预定了你的书。我正在等待正式发布。
    【解决方案2】:

    存储属性是一个属性,其属性值与类或结构的实例一起存储。值可以更改,但属性也可以是常数。因此,存储的属性可以很简单:

    var proA: Int
    let proB: Int
    var proC: Int = 0
    

    计算属性不存储值。因此,您不能为计算属性分配值。 Computed 属性应该有一个返回值的 getter。我是一个广义的术语,您可以将计算属性视为返回函数值的属性。

    计算属性示例

    var proA: Int {
        return proB * proC
    }
    

    关于您的问题:

    1. 计算属性因此是一个不存储值的属性,并且包含一个 get 以返回该属性的“计算”值。
    2. a 是正确的,b 计算属性不应该有初始化,c 如果你的意思是 willSet 和 didSet。是的,它们就像观察者,观察属性的值何时发生变化并分别发生变化
    3. 由于计算属性的值不会被存储并且永远不会被使用,因此编译器会禁止它。

    希望这会有所帮助。

    【讨论】:

    • 感谢您的回答:)
    【解决方案3】:
    1. 我想知道是什么让属性成为计算属性?只要属性有一个 getter 并返回它就是一个计算属性,这是否正确?

    如果您在属性声明中定义get { },它将将该属性变为计算属性。 而且它不能有初始值,因为当你访问属性时,它总是会调用属性中声明的get{}函数。

    1. 我的所有理解(a、b 和 c)都正确吗?如果不是,请您指出

      • a 是正确的
      • b 错了。

      您不能为计算属性设置初始值。 因为正如我在问题 1 中解释的那样,当您需要访问该属性时,它总是会返回 get{} 的结果。

      • c : 50% 正确

      setter ,它也可以用来将newValue 存储到另一个私有变量中,你可以做一些额外的observing 逻辑。因此,要观察存储属性的值变化,请使用 willSetdidSet 您可以在 set{} 声明的计算属性(具有 gettersetter)上定义 observing 逻辑。但set {} 的主要目的是将值存储到另一个变量或例如UserDefaults

    2. 为什么不允许初始化计算属性? (请看下图)当我这样做时,编译器会发出警告 Cannot call value of none-function type "int" 这个错误是什么意思?

      同样的答案

      您的代码使编译器感到困惑 当您在声明时为属性设置初始值时,编译器会尝试将其理解为stored 属性。但是您还为此属性定义了get{},这意味着它是计算属性,并且在您访问该属性时应该始终返回22。所以你应该删除两个之一。

    【讨论】:

    • 嗨,Alex,感谢您的帮助,非常详细的信息 :)
    • 谢谢,我很高兴 :)
    【解决方案4】:

    一个。是的,只有观察者的属性是存储属性而不是计算属性。因为属性观察者跟踪其值先前已初始化且现在正在更改的属性的值,这是一个存储属性。它不适用于计算属性,因为它没有预定义值

    b.计算属性是一个值依赖于其他变量的属性,我们应该只将那些属性声明为计算属性,需要使用另一个变量的值来计算,所以它的值不能提前初始化。 例如- 如果我们有 2 个变量 a 和 b。我们需要它们的相加值,因此使用了一个名为“sum”的变量,然后 sum 将被声明为计算属性,其 get{} 块将返回 (a+b),即 a 和 b 的总和以及 sum 变量的值.那么在这种情况下我们不能初始化属性'sum' 提前,因为它将使用 a & b 计算。

    c。 Setter 不是观察者,它设置另一个变量的值或执行与其他变量相关的一些操作,而属性观察者跟踪其关联变量本身的值的变化。例如如第 b 点所述,对变量“sum”使用属性观察器是没有意义的。

    【讨论】:

      猜你喜欢
      • 2020-03-03
      • 2016-04-22
      • 2018-07-29
      • 2014-08-02
      • 2019-09-10
      • 1970-01-01
      • 2019-02-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多