Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I use didSet in deinit?

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?

like image 367
Damian Dudycz Avatar asked Oct 15 '18 16:10

Damian Dudycz


People also ask

Is didSet called in init Swift?

One thing to note is that willSet and didSet will never get called on setting the initial value of the property. It will only get called whenever you set the property by assigning a new value to it. It will always get called even if you assign the same value to it multiple times.

Does didSet get called on init?

Apple's docs specify that: willSet and didSet observers are not called when a property is first initialized. They are only called when the property's value is set outside of an initialization context.

What does didSet mean in Swift?

In Swift, didSet and willSet methods act as property observers. willSet runs a piece of code right before a property changes. didSet runs a piece of code right after the property has changed.

Did set will set?

willSet is called before the data is actually changed and it has a default constant newValue which shows the value that is going to be set. didSet is called right after the data is stored and it has a default constant oldValue which shows the previous value that is overwritten.


1 Answers

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.

like image 187
matt Avatar answered Sep 18 '22 20:09

matt