简体   繁体   English

当我设置该属性的属性时,为什么在属性上调用'didset'?

[英]Why is 'didset' called on a property when I set the property of that property?

In this code when the text changes, titleEditingChanged is called (as expected). 在此代码中,当文本更改时,将调用titleEditingChanged (如预期的那样)。 But when it executes the line 但是当它执行该行时

investment?.title = sender.text!

it calls the didset{} of Investment . 它称Investmentdidset{} Why? 为什么?

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!
}

Property observers of value types (eg structures) are called also when an underlying property of the type instance is set; 当设置类型实例的底层属性时,也会调用值类型 (例如结构)的属性观察者; simply since the value of the instance itself is updated . 只是因为实例本身值已更新 The same does not hold for reference types ; 同样不适用于参考类型 ; as long as the reference itself is not mutated, the property observer will not be called (ie, the reference itself can be considered the value of reference types). 只要引用本身没有变异,就不会调用属性观察者(即,引用本身可以被认为是引用类型的值)。

From Language Guide - Properties - Property Observers we read: 语言指南 - 属性 -我们读到的属性观察者

Property observers observe and respond to changes in a property's value . 财产观察员观察并回应财产价值的变化 Property observers are called every time a property's value is set, even if the new value is the same as the property's current value 每次设置属性值时都会调用属性观察者,即使新值与属性的当前值相同


To verify the above, consider the following example: 要验证上述内容,请考虑以下示例:

/* 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)"

Hence, we can infer that your custom type Investment is a value type (a structure), and the didSet property observer of the instance investment of this type (in your UITableViewCell subclass) will be called even if you only set/update underlying properties of investment . 因此,我们可以推断出您的自定义类型Investment是一种值类型(结构),并且即使您只设置/更新此基础属性,也将调用此类型实例investmentdidSet属性观察者(在您的UITableViewCell子类中) investment If you'd like to avoid this, change Investment into a reference type (class), in which case the didSet property observer will only be changed if the investment instance itself is set/updated. 如果您想避免这种情况, didSet Investment更改为引用类型(类),在这种情况下,只有在设置/更新investment实例本身时才会更改didSet属性观察者。

It is called because Investment is probably a struct, not a class. 这是因为Investment可能是一个结构,而不是一个类。 In Swift structs are value types, not reference types as classes. 在Swift中,结构是值类型,而不是类的引用类型。 So, structs are not "mutable in place". 因此,结构不是“可变的”。

It means that whenever you change a struct property a new struct object is allocated to replace the current one, the current object data is copied to the new one except for the changed property that will contain the new value set. 这意味着每当您更改struct属性时,都会分配一个新的struct对象来替换当前的对象,当前的对象数据将被复制到新的对象数据,但更改的属性将包含新的值集。

Remember that the compiler does not let you change a struct property whenever you initialize a struct object with a let command (with a class you can do it). 请记住,每当使用let命令初始化struct对象时,编译器都不允许您更改struct属性(使用类可以执行此操作)。

That explains why the observer is called whenever you change a struct property. 这就解释了为什么每次更改struct属性时都会调用观察者。 Once a new struct object is allocated to replace the current one, it will now be stored in another memory block, so its value will be changed and the didSet observer will be called. 一旦分配了新的struct对象来替换当前的对象,它现在将被存储在另一个内存块中,因此它的值将被更改并且将调用didSet观察者。

PS: It will not happen if you define Investment as a class instead of a struct. PS:如果将Investment定义为类而不是结构,则不会发生这种情况。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM