Inner didSet protection bizarrely extends to the whole class?
This is bug SR-419.
From the comment on the bug:
Ugh. We really need to check that the base of the property access is statically
self
.
and from my experiments it seems that the didSet
observer is not invoked only if you set the same property on any object. If you set any other property (even on the same object), the observer is invoked correctly.
class A {
var name: String
var related: A?
var property1: Int = 0 {
didSet {
print("\(name), setting property 1: \(property1)")
self.property2 = 100 * property1
related?.property1 = 10 * property1
related?.property2 = 100 * property1
}
}
var property2: Int = 0 {
didSet {
print("\(name), setting property 2: \(property2)")
}
}
init(name: String) {
self.name = name
}
}
let a = A(name: "Base")
a.related = A(name: "Related")
a.property1 = 2
Output:
Base, setting property 1: 2
Base, setting property 2: 200
Related, setting property 2: 200
when the expected output should be:
Base, setting property 1: 2
Base, setting property 2: 200
Related, setting property 1: 20
Related, setting property 2: 2000
Related, setting property 2: 200
It seems you also need to assign that property directly from the observer. Once you enter another function (or observer), the observers start working again:
var property1: Int = 0 {
didSet {
print("\(name), setting property 1: \(property1)")
onSet()
}
}
...
func onSet() {
self.property2 = 100 * property1
related?.property1 = 10 * property1
related?.property2 = 100 * property1
}
And that is the best workaround.
Another workaround (thanks @Hamish) is to wrap nested assignments into an immediately executed closure:
var property1: Int = 0 {
didSet {
{
self.property2 = 100 * property1
related?.property1 = 10 * property1
related?.property2 = 100 * property1
}()
}
}
Depending on code before the closure, you might have to wrap it into parenthesis or insert a semicolon after the preceding statement.
Why no Infinite loop in didSet?
If you check Apple's documentation for Swift in The Swift Programming Language - Properties, Apple says that:
Note:
If you assign a value to a property within its own didSet observer, the new value that you assign will replace the one that was just set.
So if you put a breakpoint in the first line of your didSet
block, I believe it should only be called once.
Related Topics
Tableview Image Content Selection Color
Cocoapods Framework with Dependencies - Include of Non-Modular Header Inside Framework Module
Flipping The Positions of Items in a UIstackview
Cannot Convert Value of Type 'X' to Expected Argument Type 'X'
How to Define a Variable in a Swift If Statement
Url(String:) Cannot Call Value of Non-Function Type 'string'
Accessibility Custom Actions Aren't Announced in Swift
Uidatepicker Show Only Sunday's Date Only
Struct Memberwise Initialization - Omitting Values for Properties That Have Defaults
Editing a Package Dependency as a Local Package
How to Return Subscript in Constant Time
Testing a Timer in Xcode with Xctest
Storagemetadata' Has No Member 'Downloadurl'
Swiftui: UIimage (Qrcode) Does Not Load After Calling Function
Detect What Is The Location of The Tap/Press Inside UIbutton Inside Sender Action Method
How Are Swift Enums Implemented Internally
Audiokit - Temporary File Size Is Too Big
Loading Image from Assets to Nsimage Keep Getting Error, Expecting Nsimage.Name