How to prevent Timer slowing down in background
This is because of the App Nap. You can disable App Nap but it is not recommended.
var activity: NSObjectProtocol?
activity = ProcessInfo().beginActivity(options: .userInitiatedAllowingIdleSystemSleep, reason: "Timer delay")
The default tolerance value of timer is zero but The system reserves the right to apply a small amount of tolerance to certain timers regardless of the value of tolerance property.
Prevent NSTimer firing delays in background app
This is App Nap. The display app can do the following to avoid napping:
id activity = [[NSProcessInfo processInfo] beginActivityWithOptions:NSActivityUserInitiatedAllowingIdleSystemSleep reason:@"whatever"];
When it can allow napping again, you should do:
[[NSProcessInfo processInfo] endActivity:activity];
OS X Cocoa timer not fired when application on background
Use beginActivityWithOptions:reason: to disable app nap for your application.
Chrome: timeouts/interval suspended in background tabs?
I recently asked about this and it is behaviour by design. When a tab is inactive, only at a maximum of once per second the function is called. Here is the code change.
Perhaps this will help:
How can I make setInterval also work when a tab is inactive in Chrome?
TL;DR: use Web Workers.
Why timer invoke its block so quickly sometimes
To understand the behavior, you need to understand how NSTimer
and RunLoop
works. In simple terms, a RunLoop
would check if the Timer should fire, if yes it would notify the Timer to fire the selector, else it won't. Now, since you are on the background, your RunLoop
is not checking for events so it won't be able to notify the Timer. But once it goes to foreground, it would see that it would need to notify the Timer even if it passed the fireDate.
TimeLine Diagram:
Let A(5th second) and B(10th second) be timer fire events. Scheduled on a timer Timer.scheduledTimer(withTimeInterval: 5.0, repeats: true)
C is entered background (0 seconds)
D be coming back to foreground (9th second, between A and B).
-----> A ------> B
C--------->D
Explanation:
On C, the RunLoop would be paused. Therefore Event A is not able to be processed until the RunLoop has resumed processing, which is on Event D. Upon Event D, it will see that Event A should fire so it would notify the Timer. After a second, the RunLoop would see that Event B has happened so it would notify the Timer again. This scenario explains why your events are printing in a second's interval. It is just the delayed event handling that makes it seem that it fired earlier, when in reality it was processed late.
Apple Doc:
A timer is not a real-time mechanism. If a timer’s firing time occurs
during a long run loop callout or while the run loop is in a mode that
isn't monitoring the timer, the timer doesn't fire until the next time
the run loop checks the timer. Therefore, the actual time at which a
timer fires can be significantly later.
resources: What is an NSTimer's behavior when the app is backgrounded?, NSRunLoop and Timer Docs
Suggestions:
Stop your timer once app goes background, but store the fireDate
. Once coming back to foreground, check if fireDate
is past Date()
. Then create a new Timer to handle events while on foreground.
JavaScript setTimeout() slows down under heavy load
Here is an article from Google where the author discusses their work on timers for Gmail. They found that having a single high-frequency timer was faster than using multiple timers if they had heavy and rapid timer use.
You could have one timer that fires every 5ms, and add all of your elements that need to be faded to a data structure that tracks where they are in the fading process. Then your one timer can look through that list and perform the next fade for each element each time it is triggered.
On the other hand, have you tried using a library like Mootools or JQuery rather than rolling your own animation framework? Their developers have put a lot of work into optimizing these kinds of operations.
Related Topics
Swift Access to Variable Length Array
What Is the Use of the Validate() Method in Alamofire.Request
How to Generate Random Numbers Without Repetition in Swift
How to Embed Third Party Framework on Ionic Capacitor Custom Plugin
How to Encode an Unmanaged<Seckey> to Base64 to Send to Another Server
Collectionview Not Display Data After Parsing JSON
A Switch Bug in Swift? - "Switch Must Be Exhaustive, Consider Adding a Default Clause."
Nsjsonserialization Not Working as Expected in a Playground
Wkwebview: How to Handle Blob Url
How to Print Call Stack in Swift
Why Swift Closure Not Capture Self
Using Compiler Variables in Swift
Firebase Completion Listeners in Swift
Swift: Double Conversion Inconsistency. How to Correctly Compare Doubles
How to Delete an Item in a Collection View with a Button in the Cell