Issue with Timer in a BGAppRefreshTask

I have a BGAppRefreshTask that is executing an operation.

The operation calls a custom class that performs some tasks and also initiates a 10 seconds timer that is a timeout fallback in this custom class.

When I make use of the custom class in other context than the background task, the timer is properly executing and the timeout logic is effective.

But in the context of the BGAppRefreshTask, that I'm testing through the XCode "_simulateLaunchForTaskWithIdentifier" command, the Timer is without effect - although returning no error when set.

I'm starting the timer with the following line of code:

RunLoop.current.add(self.timeout_timer!, forMode: RunLoop.Mode.common)

The operation is not being interrupted or cancelled, so I believe both the custom class instance (that contains a function the timer will run when expiring) and the reference to the timer are properly retained.

I wonder if there is a specific limitation, or thread issue in the context of a BGAppRefreshTask.

Answered by alexdoo in 740765022

Responding to myself: there is no active runloop associated to a background task thread, so after adding the timer to the runloop, I also need to start it with

RunLoop.current.run()

Wondering if it is a safe thing to do only based on the context not being the main thread:

if Thread.current.isMainThread == false {
      RunLoop.current.run()
    }
Accepted Answer

Responding to myself: there is no active runloop associated to a background task thread, so after adding the timer to the runloop, I also need to start it with

RunLoop.current.run()

Wondering if it is a safe thing to do only based on the context not being the main thread:

if Thread.current.isMainThread == false {
      RunLoop.current.run()
    }

there is no active runloop associated to a background task thread

Right.

so after adding the timer to the runloop, I also need to start it with

Oh, that’s a bit of a worry. You should not, in general, run the run loop like this.

Wondering if it is a safe thing to do only based on the context not being the main thread

That’s an exercise fraught with much peril. There are two alternatives I recommend:

  • Use a timer that doesn’t rely on the run loop.

  • Bounce to a thread, like the main thread, that you know is running the run loop, and then schedule your timer from there.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Issue with Timer in a BGAppRefreshTask
 
 
Q