Any ideas why this is happening?
The short answer is that in your case, you perform actions (animations) based on the unsynchronized push model, and the mechanism you use is not suitable for the task you are performing.
Additional notes:
NSTimer
has a low resolution.- Your work is done in the main run loop. The timer may not fire when you expect it, because a lot of time can be spent while working on this thread, which blocks your timer from being triggered. Other system actions or even threads in your process can make this option even bigger.
- Unsynchronized updates can lead to a lot of unnecessary work or variability, because the updates that you perform in your callback are published some time after they appear. This adds even more changes to the accuracy of synchronization of your updates. Itβs easy to finish dropping frames or do a significant amount of unnecessary work when updates aren't syncing. This cost may not appear until your drawing is optimized.
From NSTimer
docs (highlighting mine):
A timer is not a real-time mechanism ; it only fires when one of the run cycle modes to which the timer has been added is running, and it can check whether the timers have elapsed. Due to various input sources, a typical trigger cycle is controlled, the effective resolution of the time interval for the timer is limited to about 50-100 milliseconds . If, during a long callout, timers are triggered or when the cycle cycle is in a mode that the timer does not control, the timer does not work until the next timer test cycle. Thus, the actual time during which the timer can be triggered can be a significant period of time after the planned firing time .
The best way to fix the problem if you are ready to optimize your drawing as well is to use CADisplayLink
, as others have mentioned. CADisplayLink
is a special βtimerβ on iOS that executes your feedback message when (able) sharing the screen refresh rate. This allows you to synchronize animation updates with screen updates. This callback is executed in the main thread. Note. This object is not very convenient for OS X, where there may be several displays ( CVDisplayLink
).
So, you can start by creating a link to the image and in your callback, do the work that will concern your animations and related tasks (for example, perform any necessary updates -setNeedsDisplayInRect:
. Make sure your work is very fast, and that your rendering is also fast - then you should be able to achieve high frame rates. Avoid slow operations in this callback (like io file and network requests).
One final note: I try to copy my timer-synchronized callbacks into a single meta-callback, instead of setting a lot of timers on the startup loops (for example, running at different frequencies). If your implementations can quickly determine what updates to do at the moment, this can significantly reduce the number of timers you set (up to one).
source share