6

让我们从代码片段开始:

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:计算属性不能有初始化(见上面代码的注释)。

c: setter 相当于属性观察者,属性观察者只是变异前后的 setter + 观察者。

问题:

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

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

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

在此处输入图像描述

非常感谢。

4

4 回答 4

4

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

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

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

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


好的,关于你的问题:

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

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

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

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

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

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

于 2016-10-11T20:40:25.637 回答
3

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

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. 由于计算属性的值不会被存储并且永远不会被使用,因此编译器会禁止它。

希望这个对你有帮助。

于 2016-10-11T20:44:06.537 回答
1
  1. 我想知道是什么使属性成为计算属性?只要属性有一个getter并返回它是一个计算属性是正确的吗?

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

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

    • a是正确的
    • b 是错误的。

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

    • c : 50% 正确

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

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

    相同的答案

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

于 2016-10-11T20:46:24.457 回答
1

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

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

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

于 2017-07-10T17:19:15.407 回答