Is there a more elegant and/or correct way to do this?
Not that I’m aware of. I’ve found
performExpiringActivity(withReason:using:)to be very difficult to use in practice, and so I generally prefer to use the older
UIApplicationbackground task API (although that API is not with its pitfalls). However, if you’re working on library code than you may not be able to rely on
UIApplication(for example, if your\ library is loaded in an app extension).
I could add more book-keeping variables to guard against this
Even doing that is surprisingly hard. The issue is that the two block invocations — to first to run the activity and the second if it expires — are run on different queues, so this bookkeeping has to be thread safe.
How short is your operation? If it’s short in human terms (0.1 second or less), your best option is to simply ignore expiry. You seem to be doing that right now, but getting tripped up by your placement of the
resumecall. I have concerns about its placement anyway. The code snippet you posted has the resume nested within the timer’s event handler, which means that the time will only be resumed if it fires. But it can’t fire because it was never resumed.
Share and Enjoy
Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware
let myEmail = "eskimo" + "1" + "@apple.com"
"The code snippet you posted has the resume nested within the timer’s event handler, which means that the time will only be resumed if it fires. But it can’t fire because it was never resumed."
Ah, that was a typo actually. I've corrected it now to include the timer.suspend() before the activity block (which still has the problem I've described above).
What I really want here is for the timer's logic, including the activity block, to not be re-entrant. Overall, the timer should not fire again until the logic in the activity block has completed or expired.