2016-03-08 87 views
8

在该代码时,该文本的变化,titleEditingChanged被调用(如预期)。但是,当它执行线为什么'didset'在设置属性属性时会调用属性?

investment?.title = sender.text! 

它调用的Investmentdidset{}。 为什么?

class InvestmentCell: UITableViewCell { 

    var investment: Investment? { 
     didSet { 
      // setup UI elements from class properties 
      textField.text = investment?.title 
      valueField.text = investment?.value?.description 
     } 
    } 

    @IBAction func titleEditingChanged(sender: UITextField) { 
     investment?.title = sender.text! 
    } 

    @IBOutlet weak var textField: UITextField! 
    @IBOutlet weak var valueField: UITextField! 
} 
+0

“投资”是类还是结构? – EmilioPelaez

+0

这是正常行为。当你将一个项目追加到一个数组时,也会发生同样的情况。 –

+2

'didSet'和'willSet'是属性观察者*。你可以在[Swift Book](https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Properties.html)中准备好他们。 –

回答

7

这就是所谓的,因为Investment可能是一个结构,而不是一类。 在Swift中,结构是值类型,而不是类的引用类型。 所以,结构不是“可变的”。

这意味着,只要你改变一个结构属性的新结构对象被分配给替换当前,当前对象的数据被复制到除了更改的属性将包含新值,设置新的。

请记住,只要使用let命令(使用可执行的类)初始化struct对象,编译器不会让您更改struct属性。

这就是为什么每当你改变一个结构属性观察者被调用。一旦一个新的结构对象被分配来替换当前的结构对象,它现在将被存储在另一个内存块中,所以它的值将被改变并且将被调用。

PS:如果您将Investment定义为类而不是结构,则不会发生这种情况。

+1

我按照你的建议做了,并把struct Investment改为class Investment,它有着理想的效果。 – ziggyzoggy

+2

另外请注意,像String,Array,Dictionary和Set这样的标准类型都是值类型。因此拥有这些类型的属性也会使didSet观察者在属性上调用任何访问权限。 (这给了我很多头痛) – codingFriend1

12

值类型(例如结构)的属性观察员也被称为当类型实例的下层属性设置;因为实例本身的值更新为。同样的不适用于参考类型;只要引用本身没有变异,属性观察者就不会被调用(即引用本身可以被认为是引用类型的值)。

Language Guide - Properties - Property Observers我们读到:

地产观察者观察和对财产的价值 变化做出反应。地产观察家称为每一个属性的值是 设定的时间,即使新的值相同属性的当前值


为了验证上述,考虑下面的例子:

/* reference type */ 
class InvestmentC { 
    var title: String = "Foo" 
} 

/* value type */ 
struct InvestmentS { 
    var title: String = "bar" 
} 

class InvestmentContainer { 
    var investmentC : InvestmentC { 
     didSet { 
      print("did set a property of 'InvestmentC' instance (ref. type)") 
     } 
    } 

    var investmentS : InvestmentS { 
     didSet { 
      print("did set a property of 'InvestmentS' instance (val. type)") 
     } 
    } 

    init() { 
     investmentC = InvestmentC() 
     investmentS = InvestmentS() 
    } 
} 

/* Example: property observer called only when setting a property 
      of the value type instance 'investmentC'    */ 
let foo = InvestmentContainer() 
foo.investmentC.title = "foobar" // prints: nothing 
foo.investmentS.title = "foobar" // prints: "did set a property of 'InvestmentS' instance (val. type)" 

因此,我们可以推断出你的自定义类型Investment是值类型(结构),和实例的didSet财产观察员即使您只设置/更新investment的基础属性,此类型的0(在您的UITableViewCell子类中)也会被调用。如果你想避免这种情况,改变Investment为引用类型(类),在这种情况下,如果investment实例本身设置/更新didSet财产观察者才会发生改变。

+0

这是一个很好的答案,但最终我选择了给Jorg B Jorge打勾,因为我发现它更加简洁和快速地理解问题。但你的回答更全面,也帮助我理解和解决问题。投资是一个结构,我确实把它改成了一个类,我找到了更透明的方式来编码它。谢谢。 – ziggyzoggy