为什么在设置属性的属性时调用该属性的"didset"?

  • 本文关键字:属性 didset 调用 设置 ios swift
  • 更新时间 :
  • 英文 :


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

investment?.title = sender.text!

它称之为Investment didset{}。为什么?

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!
}
之所以

调用它,是因为Investment可能是一个结构体,而不是一个类。在 Swift 结构中,结构是值类型,而不是作为类的引用类型。因此,结构不是"就地可变的"。

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

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

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

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

当设置类型实例的基础属性时,也会调用值类型(例如结构)的属性观察器;仅仅是因为实例本身的值已更新对于引用类型,情况并非如此;只要引用本身没有改变,就不会调用属性观察者(即引用本身可以被认为是引用类型的值)。

从语言指南 - 属性 - 属性观察者中,我们阅读:

属性观察

者观察并响应属性的更改 值。每次属性的值为 设置,即使新值与属性的当前值相同


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

/* 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是一个值类型(结构),即使您只设置/更新 investment 的基础属性,也会调用此类型的实例investment(在您的UITableViewCell子类中)的didSet属性观察器。如果要避免这种情况,请将Investment更改为引用类型(类),在这种情况下,仅当设置/更新investment实例本身时,才会更改didSet属性观察器。

最新更新