Xojo.Core.Timer.CallLater Unreliable

Hey all,

I am wondering if anyone else has found the Xojo.Core.Timer.CallLater method to be totally unreliable? This method has done nothing but cause me grief in my apps but none of it is reproducible so that I can create a project for Xojo to have them fix it.

I have gotten Dictionary Iteration exceptions with it. I’ve had some nil object exceptions that I tied directly to the timer. And in my latest, I had a clear call to a method that would fire fine on OS X, but never in Windows. It’s downright embarrassing to have customers complain that a function isn’t working and it’s due to the fact that my framework vendor, Xojo, has put an unreliable method call in their toolkit.

I keep getting burned by this method and I am learning to gradually remove it 100% from my apps. I find that standard traditional timers to be much more reliable or the SingleActionTimer class developed KAtkoSoft. Karen’s class seems to be much more reliable than Xojo’s and frankly, that is sad.

I am wondering if anyone else has seen this type of behavior or is my experience an anomaly?

[quote=395957:@Jon Ogden]Hey all,

I am wondering if anyone else has found the Xojo.Core.Timer.CallLater method to be totally unreliable? This method has done nothing but cause me grief in my apps but none of it is reproducible so that I can create a project for Xojo to have them fix it.

I have gotten Dictionary Iteration exceptions with it. I’ve had some nil object exceptions that I tied directly to the timer. And in my latest, I had a clear call to a method that would fire fine on OS X, but never in Windows. It’s downright embarrassing to have customers complain that a function isn’t working and it’s due to the fact that my framework vendor, Xojo, has put an unreliable method call in their toolkit.

I keep getting burned by this method and I am learning to gradually remove it 100% from my apps. I find that standard traditional timers to be much more reliable or the SingleActionTimer class developed KAtkoSoft. Karen’s class seems to be much more reliable than Xojo’s and frankly, that is sad.

I am wondering if anyone else has seen this type of behavior or is my experience an anomaly?[/quote]
The only way I can imagine that you’re getting these types of exceptions is if the target object is going out of scope before the timer fires.

Also make sure that you dont have anything in your paint routines that arent graphics related calls. If you accidentally have infinite paints you can fill or jam the event queue which timers use to trigger things (in windows at least)

@Greg O’Lone would you please take a look at this Feedback report <https://xojo.com/issue/40246>. It was created by Jon and it’s still a bug which causes me a lot of problems too. The report has been closed and marked as a duplicate of another report, 49717, but that’s incorrect as 49717 is not the same thing and it has been marked non-reproducible. So while 40246 is reproducible, because it’s been closed as a duplicate of a non-reproducible report, it isn’t going to be fixed.

In summary, would somebody please reopen 40246 so it gets fixed?!?! :slight_smile:

In theory it is of great utility. I have found though that timers were inconsistent when using them heavily. I also lean against using them now.

Sure, just did. Using Sam’s project (since that’s the only sample that was supplied), this doesn’t look like a bug to me.
The code that’s causing the problem is this:

Dim n As New dummy Xojo.core.timer.calllater( 1000, weakAddressOf n.testMethod )
When that code runs, n is allocated, CallLater is set up to call n.testmethod in about a second and then the method ends and n goes out of scope. When the timer finally gets called, you get a NilObjectException down in the bowels of the framework because the delegate method no longer exists.

What do you expect to happen in this case?

You’re not alone and like @Greg O’Lone says, a lot of the problems I was having were due to edge cases where the object was going out of scope before the callLater was firing.

To be safe, 99% of the time, I prefer to use timers within the object just to prevent this.

@Greg O’Lone I go over it in this thread. I understand that the method is out of scope but, as you yourself suggest (in the thread linked above), a try/catch should resolve this and it certainly does if you use a Timer other than the shared CallLater method. The problem is that the CallLater method does not seem to use a try/catch so it cascades into the App’s UnhandledException event.

No, but on Windows Calllater calls are processed in the reversed order compared to macOS which makes actions that trigger later called methods in a loop a bit tricky: <https://xojo.com/issue/52208>

The problem I see in this specific case is that a Calllater call tries to invoke a delegate implicitly. n is created in this example and so n.testmethod exists, but when Calllater fires it tries to run code that does not exist anymore. You probably get a segmentation fault. Which does seem logical to me and not so much a bug, though it would be good if segfaults of this type could be caught.
I wonder if you – if the code example above is useful at all because it rather looks like it should crash 100% of the time – could handle this problem by adding a Xojo.Core.Timer.CancelCall WeakAddressOf me.TestMethod in dummy’s destructor?

You don’t. It’s a NilObjectException because n is nil.

Thanks for the clarification. Still Xojo’s behavior makes sense to me. You cannot trap a Calllater invocation because the try/catch clause will have been processed when Calllater fires. So you must either ensure that the delegates persist like putting them in a retain dictionary or cancel their invocation in their destructor.

Lets say we do use a try/catch in effect, what do you want us to do with the exception?

Here’s the issue I see… lets say you want to know that the object has gone away. As soon as we add an internal try/catch which effectively throws away the exception, you as developers no longer have a way to tell that the object has gone away and that the code that’s the target of the Timer isn’t running.

If you want the object to stick around long enough, use AddressOf.

So let’s take a look in my case that I just discovered this week where the object is definitely NOT nil. Here’s most of my code from a method that creates a number of canvases that get painted to a window:

  For j as integer = 0 to NumberOfRows-1
    For i as integer = 0 to NumberOfColumns-1

      If k > MaxItems Then
        Exit
      End If
      
      Dim SourceArrayIndex As Integer
  
      If Create Then
        v = New ViewCanvas  // Create a new canvas
        v.SourceDevice = SourceDeviceArray(SourceArrayIndex)   // This is an object that gets assigned to the canvas
        v.SetupHandler  // Setting up all my event handlers
      Else
        v = PreviewCanvases(k)  // Not new - picking from my array of canvas objects already created
      End If
      
// Sets size of the canvas

      v.width = CanvasWidth
      v.height = CanvasHeight
      v.CanvasWidth = CanvasWidth
      v.CanvasHeight = CanvasHeight
      v.left = 0+v.width*(i)
      v.top = v.height*j
      v.originaltop = v.top
      v.OriginalLeft = v.left
      
      If Create Then
        v.OriginalWidth = CanvasWidth
        v.OriginalHeight = CanvasHeight
        self.Height = v.Top+v.Height
        CanvasWidth = v.Width
        CanvasHeight = v.Height
        v.indx = k
        v.CaptureTime = CaptureTime
        PreviewCanvases.Append v // Append the new canvas to the array
        Xojo.Core.Timer.CallLater(0,AddressOf v.DoCapture)  // THIS IS THE TIMER THAT DOES NOT FIRE IN WINDOWS!
      End If
      
      k=k+1
    Next
    
  Next
  

Now, you can’t tell me that the canvas, v, goes out of scope because it’s already happened to the array. In OS X, this works fine. In windows, the timer never fires.

[quote=396031:@Greg O’Lone]Sure, just did. Using Sam’s project (since that’s the only sample that was supplied), this doesn’t look like a bug to me.
The code that’s causing the problem is this:

Dim n As New dummy Xojo.core.timer.calllater( 1000, weakAddressOf n.testMethod )
When that code runs, n is allocated, CallLater is set up to call n.testmethod in about a second and then the method ends and n goes out of scope. When the timer finally gets called, you get a NilObjectException down in the bowels of the framework because the delegate method no longer exists.

What do you expect to happen in this case?[/quote]

OK, so this was Sam’s code and not mine. I should go back and look at my code and see what was happening. I am pretty sure that in my code, I am not operating on an object created like the code above. Yes, it some ways, I would expect that object to go out of scope, but…

Since you have created the timer, I would think you would still have a reference to that object as you have passed in a method from the object into the timer creation. So that link is created before the object goes out of scope, so I would think the object would still exist.

But I am pretty sure in my case that is not happening. I’ll need to look at that again.

Not if you use WeakAddressOf. That’s the whole point.

Yeah, that’s a good point. You are correct.

Let me go check my part of the code in that Nil object exception thing. If it’s what I am thinking of, no object is going NIL and the timers will fire hundreds or thousands of times and then maybe after a day or two of it running, you get this. I’ve eliminated using the timer because of this. I can find nothing wrong with my code.

I just reviewed your code and I do see a way for things to get into a bad state.

If Create is ever true, v gets reinitialized, making the previous version (which is what you used AddressOf on) no longer have a reference. It’ll still exist as long as the timer hasn’t fired, but as soon as it does, I suspect it goes out of scope and disappears.

So how often is Create set to True? and can it be set that way while the i and j loops are running?

[quote=396202:@Greg O’Lone]I just reviewed your code and I do see a way for things to get into a bad state.

If Create is ever true, v gets reinitialized, making the previous version (which is what you used AddressOf on) no longer have a reference. It’ll still exist as long as the timer hasn’t fired, but as soon as it does, I suspect it goes out of scope and disappears.

So how often is Create set to True? and can it be set that way while the i and j loops are running?[/quote]

Create is set to true as a method parameter. When the window is first being initialized, the method is called with create set to True. Then every time the window is resized, the method is called again but this time since the canvases all exist, we don’t set create to True. We just resize everything.

And no, it doesn’t/can’t get changed during the loop execution.

Finally, Greg, in this case in Windows, I don’t get an NOE. It fails silently. The timer never fires.

Are you aware that when Create = True, Xojo.Core.Timer.CallLater(0,AddressOf v.DoCapture) gets called over and over for each iteration of i and j ?

Uh, yes, Greg. It’s designed to do that. Please don’t treat me like I am some idiot. Each canvas I draw runs a process that grabs an image from a device on the network. So I create the image and start that process. That’s how I start the process. I wanted it to fire in a timer so that the iteration of the loop is not held up by each process starting.

But you know what. Forget it. I just found another spot where I have been getting errors that I can’t figure out and guess what - It’s your doggone CallLater method of Xojo.Core.Timer. And this time it is saying that a canvas that I place in the IDE is NIL. How the hell can something I place on the window in the IDE that doesn’t ever get closed go Nil?

So I am just going to avoid using this freaking call because it’s broke somewhere internally and you guys refuse to acknowledge that maybe you have a problem with it. No, it’s always our fault because we can’t replicate it reliably in a bug report.