New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[SR-1437] defer block in init triggers property observers #44046
Comments
Comment by Paul Eipper (JIRA) I would expect this to be the case since it's true also for other methods called from init or a closure: struct Foo {
var x: Int {
didSet {
print("Foo.x.didSet: \(oldValue) -> \(x)")
}
}
init() {
x = 1
// closure invokes didSet
({ x = 2 })()
}
}
_ = Foo() And: struct Foo {
var x: Int {
didSet {
print("Foo.x.didSet: \(oldValue) -> \(x)")
}
}
init() {
x = 1
// mutating method invokes didSet
setX(2)
}
mutating func setX(newX: Int) {
x = newX
}
}
_ = Foo() |
But a defer block isn't a method. The fact that it seems to be treated basically like a block under the hood is entirely an implementation detail, and the fact that you can observe this detail should be considered a bug. |
Comment by Paul Eipper (JIRA) From the docs:
It is pretty clear a |
That's the complete opposite of how I read it. What that quoted bit means to me is a |
To back up my interpretation, here's a bit of sample code: final class DeallocSpy {
deinit {
print("deinit")
}
}
func foo() {
let foo = DeallocSpy()
defer {
print("defer block")
}
}
foo() Under your interpretation, the output would have to be
But in fact the output is
This proves that the |
Comment by Paul Eipper (JIRA) Getting back to why observers are not called on initialization, it's because they might depend on other properties that might not be set yet. Executing from defer makes sure all initialization is done, so the observers don't have the dependency issue anymore and are cleared to trigger. |
Code executed in the 2nd step of 2-phase initialization also guarantees that all properties are set, and yet property observers are still not fired. This leads to a very simple rule: Modifying properties (that were declared on the current class) from within an initializer doesn't fire observers. And I see no reason why |
Comment by Paul Eipper (JIRA) PS: regarding the code sample, yes, it will run while the stack is still available to allow access to variables, but it will run after the defining scope has finished all execution. |
Environment
Apple Swift version 2.2 (swiftlang-703.0.18.8 clang-703.0.31)
Target: x86_64-apple-macosx10.9
Additional Detail from JIRA
md5: 606297041624b4a5d750aefd4d201953
relates to:
Issue Description:
Property observers are not normally invoked when the property is set from within
init
, but if it's set from inside adefer
block ininit
it does fire.Example:
This prints
Similarly, this can be triggered with
defer
blocks inside the property observer itself. Example:This prints
The text was updated successfully, but these errors were encountered: