I added a variable of Timer to my class, and used its didSet observer to invalidate old value
var timer: Timer? {
didSet { oldValue?.invalidate() }
}
deinit {
timer = nil
}
I thought this would be enough to invalidate timer when class is deinitialized, but looks like didSet is not called. Why is that? Are observers not working during deinitialization?
Let's put an answer here so we can close this off.
It seems that property observers apparently do not run during deinit
. This seems parallel to the fact that property observers do not run during init
, but unlike the latter, the former doesn't seem to be clearly documented anywhere.
You can work around this by semantic trickery, but don't! That seems like a bug (and I've filed it).
The original use case was not a very good one to begin with. Hiding invalidation of a timer in replacement sounds like a potential maintenance nightmare. Agreed that invalidation and replacement go together like ham and eggs, what I always do is write a method that invalidates and replaces, in that order, and funnel everything through that method. (This can be enforced if necessary, but I won't go into that.) That method can be called during deinit
.
SUPPLEMENTARY NOTE: Watch out, when using a timer, for memory management issues! You can easily get yourself into a situation where deinit
is never called, because you're retaining the timer but the timer is retaining you. You will then fail to invalidate the timer and your entire view controller will leak. You don't complain about that in your question, but it's a related matter so I thought I'd better flag it.