I have a lazy property in a struct and every time I access it, it mutates the struct.
var numbers = [1,2,3]
struct MyStruct {
lazy var items = numbers
}
class MyClass {
var myStructPropery: MyStruct = MyStruct() {
didSet {
print(myStructPropery)
}
}
}
var myClass = MyClass()
myClass.myStructPropery.items
myClass.myStructPropery.items
myClass.myStructPropery.items
Result:
Print (didSet) will be called every time.
The ideal behaviour should be first time mutation only (since that’s how lazy variables behave). Is this a bug in Swift or am I doing something wrong?
2
Answers
I started debugging this with following set up –
I can reproduce the problem on
Xcode 12.5
usingSwift 5.4
.Attempt 1 : Turn
var numbers
intolet numbers
– Does NOT work.Attempt 2 : Assign the value inline without using an extra variable – Does NOT work.
Attempt 3 : Assign the value inline using the full blown getter syntax – Does NOT work.
At this point, we are out of options to try. Even though we can clearly see that
return [1,2,3]
in the last attempt is executed exactly once, theMyClass.myStructPropery.modify
is called repeatedly on access toitems
.Maybe Swift Forums is a better place to discuss this.
What you are seeing is is that the observed property
items
has notified its observer that it has been mutated because it was accessed, and a lazy variable is by definition mutating since it will be set at a later time. ThereforedidSet
gets called to handle this.The lazy variable is actually only set once even though it signals that it has mutated and the property
myStructPropery
is only mutated once when the variable is first set but is the same instance after that.Here is how we can verify this, first change the lazy var declaration so it’s more like how we usually declare such a variable
and then add a print statement
If we now run the test code
we see that "inside lazy" only prints once. To verify that the property
myStructProperty
isn’t changed we can make the struct conform toEquatable
and perform a simple check insidedidSet
Now running the test we see that the print inside
didSet
is never executed so myStructProperty is never changed.I have no idea if this behaviour is a bug but personally it feels like it might be complicate for the property observer to stop observing a lazy property once it was accessed or for a lazy var to not be defined as mutating once it is set.