CADisplayLink and drawRect

2019-04-29 09:20发布

I need help to better understand how CADisplayLink and drawRect behave, so that I can figure out how to keep my app's framerate at a smooth 60fps. My (presumably incorrect) understanding so far is the following:

1) CADisplayLink calls a specified selector when the display refreshes (a so-called "v-sync" event; about every 16ms).

2) iOS uses double buffering, meaning that while one frame buffer is being displayed we can prepare (draw to) the other, and the two are swapped at the next v-sync event.

3) Therefore, from the time the display link fires, I have about 16ms to ensure that all calculations and drawing required for the next frame has been completed, so that everything is ready by the time the buffers are swapped and the screen refreshes.

4) The drawRect method of a custom UIView draws to the back buffer, so any custom drawing is displayed at the next v-sync event after the drawRect method is called.

Is this how it really works? (And what happens if the next v-sync event happens before I've finished drawing to the back buffer?)

Then, how should I use CADisplayLink to redraw custom UIViews? I've tried calling setNeedsDisplay whenever the display link fires, but there's a delay before the drawRect method actually begins:

2014-12-10 19:17:21.000 myApp[39487:60b] Display link fired.
2014-12-10 19:17:21.001 myApp[39487:60b] Sending setNeedsDisplay
2014-12-10 19:17:21.012 myApp[39487:60b] drawRect beginning
2014-12-10 19:17:21.013 myApp[39487:60b] drawRect finished
2014-12-10 19:17:21.017 myApp[39487:60b] Display link fired.
2014-12-10 19:17:21.018 myApp[39487:60b] Sending setNeedsDisplay
2014-12-10 19:17:21.029 myApp[39487:60b] drawRect beginning
2014-12-10 19:17:21.031 myApp[39487:60b] drawRect finished
2014-12-10 19:17:21.033 myApp[39487:60b] Display link fired.

This is a very simplified example, with almost no drawing being done in the drawRect method. Some of my more complex drawRects can take up to 10ms to complete. But there are only 5ms between when drawRect starts and the next display refresh! Plus, there are 11 whole milliseconds apparently "wasted" between the display link firing and the drawRect beginning! How do I make use of that time?

If I try calling drawRect directly in the display link selector, I get something like this:

2014-12-10 19:24:41.000 myApp[39495:60b] Display link fired.
2014-12-10 19:24:41.001 myApp[39495:60b] Sending setNeedsDisplay
2014-12-10 19:24:41.002 myApp[39495:60b] drawRect beginning
2014-12-10 19:24:41.003 myApp[39495:60b] drawRect finished
2014-12-10 19:24:41.016 myApp[39495:60b] Display link fired.
2014-12-10 19:24:41.017 myApp[39495:60b] Sending setNeedsDisplay
2014-12-10 19:24:41.018 myApp[39495:60b] drawRect beginning
2014-12-10 19:24:41.020 myApp[39495:60b] drawRect finished
2014-12-10 19:24:41.032 myApp[39495:60b] Display link fired.

Now my drawing code seems to have plenty of time to execute. However, the Apple documentation states explicitly that "you should never call the drawRect method directly yourself". So why is this the wrong thing to do? And how do I make maximum use of the 16 short milliseconds I have to draw each frame?

0条回答
登录 后发表回答