How to prevent NilObjectExceptions on Quit?

I have a Control object that has as a property a code-instantiated free-running timer. The (WeakAddress) delegate for the timer’s action event raises an event which is handled by the object’s parent window . Sometimes when the app quits I get a NOE, presumably because the window is gone but the object still exists and the timer is still firing. What’s the best practice for handling such cases to ensure that timers aren’t calling code that’s been destroyed? Is it as simple as using AddressOf instead of WeakAddressOf, or is there more to it?

Tear down the Timer in the Window’s Close or CancelClose event.

2 Likes

That’s why I never use CallLater. If you have the Timer as a property, set it’s RunMode to ‘Off’ and the property to ‘nil’ in the Window’s Close event.

Edit: Not to forget to ‘RemoveHandler’.

What’s the problem with

Timer.CancelCallLater(AddressOf method)

in the window’s close event?

P.S. Actually you don’t even need that, the window and app close just fine (at least on my Mac here) with the timer still waiting to call …

It’s not a CallLater, it’s a timer that sits there firing continuously, i.e. “free-running”.

I haven’t seen the problem on Mac, only under Windows.

That sounds like it would work, but it leads to questions about what else I need to handle myself on app quit, and why doesn’t the framework handle this for you, i.e. shouldn’t it first destroy everything that can generate events at random, like timers and sockets, before destroying their parents? And if this is something the user does need to do, why is it not mentioned in the documentation?

Also, how do you tear down a timer? Set it = Nil?

Set its RunMode to off. It’s unclear to me why doing anything else would be required.

I’m not convinced that this is really the source of your trouble, but since every call to AddHandler should have a corresponding call to RemoveHandler, this is how I typically handle it:

if myTimer isa object then
  myTimer.RunMode = Timer.RunModes.Off
  RemoveHandler myTimer.Action, WeakAddressOf TimerMethod
  myTimer = nil
end if

I usually check if the controls of the window still exist in such cases. Random code example from the result of a thread:

if bbCheckImap = nil then Return ' when closing window

#Pragma BreakOnExceptions False
try
  
  bbCheckImap.Caption = kCheck
 'other code
  
catch err as NilObjectException
  'ignore, window is closing
end try
#Pragma BreakOnExceptions True

A bb control is always a BevelButton.

Any alternative hypotheses?

That I’m wrong? :slight_smile:

Let’s see if this code change fixes it.

have your Control object a Destructor Method where you can clean up something?

Do you use DoEvents anywhere?

Nice try, but no, lol!

I assume the window is closing as the app is shut down, so do you have a long process/loop/thread running during the close of the window?

No threads or “long” processes per se, but there are a few (half a dozen at most, I think) timers going, and some continuous incoming serial data bursts at 100ms intervals, each of which involves some handling.

The fault is not consistently reproducible, but Murphy will see to it that as soon as the client tests it, it will happen for them :upside_down_face:

Do you use any declares?
32 or 64 bit exe?

32-bit build. There are some declares that extract USB device info, which only get called when SerialDevice.Count changes, which should not happen as a result of the app quitting.

Which Xojo version?

2021 r2.1, under Mac Mojave.