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

zig*_*ggy 11 ios swift

在此代码中,当文本发生更改时,titleEditingChanged会调用(如预期的那样).但是当它执行该行时

investment?.title = sender.text!
Run Code Online (Sandbox Code Playgroud)

它调用didset{}Investment.为什么?

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!
}
Run Code Online (Sandbox Code Playgroud)

dfr*_*fri 14

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

语言指南 - 属性 -我们读到的属性观察者:

财产观察员观察并回应财产价值的变化.每次设置属性值时都会调用属性观察者,即使新值与属性的当前值相同


要验证上述内容,请考虑以下示例:

/* 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)"
Run Code Online (Sandbox Code Playgroud)

因此,我们可以推断您的自定义类型Investment是值类型(结构),并且即使您只设置/更新其基础属性,也将调用此类型didSet实例investment(在您的UITableViewCell子类中)的属性观察者investment.如果您想避免这种情况,请更改Investment为引用类型(类),在这种情况下,didSet只有在设置/更新investment实例本身时才会更改属性观察器.


Jor*_*rge 12

它被称为因为Investment它可能是一个结构,而不是一个类.在Swift中,结构是值类型,而不是类的引用类型.因此,结构不是"可变的".

这意味着每当您更改struct属性时,都会分配一个新的struct对象来替换当前的对象,当前的对象数据将被复制到新的对象数据,但更改的属性将包含新的值集.

请记住,每当使用let命令初始化struct对象时,编译器都不允许您更改struct属性(使用类可以执行此操作).

这就解释了为什么每次更改struct属性时都会调用观察者.一旦分配了新的struct对象来替换当前的对象,它现在将被存储在另一个内存块中,因此它的值将被更改并且didSet将调用观察者.

PS:如果你定义Investment为一个类而不是一个struct ,就不会发生这种情况.

  • 另请注意,String,Array,Dictionary和Set等标准类型都是值类型.因此,拥有这些类型的属性也会使didSet观察者调用该属性上的任何访问权限.(这让我很头疼) (2认同)