Since the Xcode 10.2 (Swift 5) the defer
statement at the end of the deinit
scope produces:
'defer' statement before end of scope always executes immediately; replace with 'do' statement to silence this warning
Let's take a look at this example:
var foo: String {
didSet {
// smt
}
}
deinit {
defer { <--- Warning
foo = bar
}
}
What's the point of this warning? - Isn't it reasonable to have the defer
statement in the deinit
? (e.g. to be able to trigger properties' observers).
The warning is correct in that the use of defer
here doesn't change the order of execution of your program, which is what the statement is designed for. It is however unfortunate that the suggested replacement otherwise changes the behaviour of your program (filed a bug: SR-10207).
It's worth noting that the use of defer
to trigger a property observer is a bit of a hack that only works because the type checker considers it to be a different context to the deinit
body. You can also achieve the same result with a closure expression:
deinit {
{ foo = bar }()
}
Ideally, there would be some form of syntax that lets you tell Swift "don't perform a direct-to-storage access here", so that such workarounds aren't necessary, but there isn't currently.
A less hacky workaround is to pull out the desired logic of the deinitialiser into a separate method, which puts the logic in a context where property accesses are done normally:
class C {
var bar = ""
var foo: String {
didSet {
// smt
}
}
init(foo: String) { self.foo = foo }
private func doDeinit() {
foo = bar
}
deinit {
doDeinit()
}
}