18

Title is quite self explanatory, but I have some animation being done in a loop triggered by CADisplayLink. However, as soon as I scroll a UIScrollView I have added to my view hierarchy, the animation stops immediately, only to return again when scrolling has completely stopped and come to a standstill....

Anyway to cancel this behaviour?

Tricky
  • 7,025
  • 5
  • 33
  • 43
  • 1
    Someone should edit the question: the class is CADisplayLink, not UIDisplayLink. – Steven Canfield Mar 26 '10 at 15:27
  • 2016 - It would seem that **.commonModes** is indeed the solution for typical modern iOS. See: stackoverflow.com/a/4878182/294884 It's quite incredible there has been no QA on this for five years – Fattie Dec 29 '16 at 13:51

8 Answers8

33

You can also mitigate the effects of this issue by using NSRunLoopCommonModes instead of NSDefaultRunLoopModes:

[displayLink addToRunLoop:[NSRunLoop currentRunLoop]
                  forMode:NSRunLoopCommonModes];
nornagon
  • 15,393
  • 18
  • 71
  • 85
  • This prevents UIScrollView receiving run-loop call during rendering, finally, stops scrolling at any time. – eonil Nov 09 '10 at 13:47
  • 1
    This does ***seem to work*** nowadays. The problem Eonil describes seems to have been resolved by Apple. What a fiasco, Apple. – Fattie Dec 29 '16 at 13:53
  • 1
    This stills fixed the issue for me – Guig Mar 01 '17 at 01:42
7

Run the display link (using -addToRunLoop:forMode:) on another thread with another run loop. So create a new thread, create a run loop on that thread, and run the CADisplayLink on that thread/run loop.

Steven Canfield
  • 7,312
  • 5
  • 35
  • 28
7

Use UITrackingRunLoopMode. It's specifically designed for scrolling stuffs.

Otherwise, just call render & present routine at -scrollViewDidScroll.

UIScrollView broken and halts scrolling with OpenGL rendering (related CADisplayLink, NSRunLoop)

Community
  • 1
  • 1
eonil
  • 83,476
  • 81
  • 317
  • 516
  • For the record, in 2016 this just doesn't work on all the devices we tested. This seems to be a solution: stackoverflow.com/a/4878182/294884 – Fattie Dec 29 '16 at 13:54
4

Actually CADisplayLink support multiple RunloopMode. try this:

    [displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:UITrackingRunLoopMode];
    [displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
ooOlly
  • 1,997
  • 21
  • 31
4

Here you can find a better (and more complex) solution:

Animation in OpenGL ES view freezes when UIScrollView is dragged on iPhone

that allows you to use 'NSRunLoopCommonModes' and avoids OpenGL freezing when holding a finger without scrolling.

This is related to what Doug found (setting the frame interval of CADisplayLink to 2 instead of 1 fixing UIScrollView).

Community
  • 1
  • 1
Ricardo Sanchez-Saez
  • 9,466
  • 8
  • 53
  • 92
2

NSRunLoopCommonModes seems to mess with the bounciness and continuous nature of the uiscrollview.

Doug
  • 21
  • 1
1

We fixed this same issue by changing the frameInterval from 1, to 2. This essentially halves the rendering rate of your OpenGL scene, but it still may render sufficiently for your needs.

frameInterval The number of frames that must pass before the display link notifies the target again.

@property(nonatomic) NSInteger frameInterval Discussion The default value is 1, which results in your application being notified at the refresh rate of the display. If the value is set to a value larger than 1, the display link notifies your application at a fraction of the native refresh rate. For example, setting the interval to 2 causes the display link to fire every other frame, providing half the frame rate.

Setting this value to less than 1 results in undefined behavior and is a programmer error.

Maurizio
  • 4,143
  • 1
  • 29
  • 28
  • How in the world does this resolve the error? The problem seems to be that animation stops. How does halving the frame rate make it run again? This would seem to be a case where 0/2=0. – OldPeculier Aug 05 '15 at 21:06
  • @OldPeculier since the display link will fire every other frame, we are able to free up CPU time for other system tasks, such as rendering the scroll view. Try it. – Maurizio Aug 06 '15 at 16:10
  • You're saying that CADisplayLink is not firing its callback because the CPU is overloaded, and that by halving the number of callbacks this lightens the CPU load such that the callback is executed. I find that...surprising. – OldPeculier Aug 06 '15 at 18:47
1

I found that if I set the frame interval to 2 instead of 1 (so 30 frames a second) everything works fine. So what I'm doing is setting it to 2 when my popover comes up and resetting it to 1 when it dismisses.

Doug
  • 11
  • 1