How to correctly stop and resume a CADisplayLink?

我的未来我决定 提交于 2019-12-21 07:15:18

问题


I figured out a big problem with CADisplayLink.

I have the most basic EAGLLayer with OpenGL ES 1.1 drawing a rotating triangle for testing. This needs a run loop method to be called at screen refresh rate, so I start the runloop like this:

- (void)startRunloop {
    if (!animating) {
        CADisplayLink *dl = [[UIScreen mainScreen] displayLinkWithTarget:self selector:@selector(drawFrame)];
        [dl setFrameInterval:1.0];
        [dl addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
        self.displayLink = dl;

        animating = YES;
    }
}

- (void)stopRunloop {
    if (animating) {
        [self.displayLink invalidate];
        self.displayLink = nil;
        animating = NO;
    }
}

When the test app launches, I call -startRunloop. When I tap the screen, I call -stopRunloop. When I tap again, I call -startRunloop. And so forth. Ping Pong.

I'm measuring how often the -drawFrame method is called in 20 seconds, and NSLog it.

  • The FIRST start / stop cycle always performs at 100%. I get the maximum frame rate.

  • All SUBSEQUENT start / stop cycles only show about 80% of the performance. I get a significantly smaller frame rate. But: Always almost exactly the same, +/- 2 frames. With no tendency to degrade further even after 50 more start / stop cycles.

In conclusion: CREATING a CADisplayLink like I do above is fine, until it's invalidated or paused. After that, any new CADisplayLink does not perform well anymore. Even if it's created new and in the exact same way as before. Same is true if I pause / resume it by calling the -setPaused: method with YES / NO.

I've made sure with Allocations and VM Tracker Instruments that there is no memory management issue. I've also checked that the -invalidate method of CADisplayLink really gets called.

iOS 4.0 on the device (iPhone 4).

Why is that? Am I missing something?


回答1:


I think you what you really want is simply to pause and unpause your display link.

 - (void)createRunloop {
    CADisplayLink *dl = [[UIScreen mainScreen] displayLinkWithTarget:self selector:@selector(drawFrame)];
    [dl setFrameInterval:1.0];
    [dl addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
    self.displayLink = dl;
    // start in running state, your choice.
    dl.paused = NO;
}
- (void)startRunloop {
    self.displayLink.paused = NO;
}
- (void)stopRunloop {
    self.displayLink.paused = YES;
}
- (void)destroyRunloop {
        [self.displayLink invalidate];
        self.displayLink = nil;
}



回答2:


I am using

[displayLink removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];

see if it works for you




回答3:


For Swift 4.2

displayLink.remove(from: RunLoop.current, forMode: RunLoop.Mode.common)



回答4:


You create a new display link instance with every start call. Have you tried just reusing the same instance?

Also, you could always just pause the display link.




回答5:


Try this in Swift,

displayLink?.remove(from: RunLoop.current, forMode: RunLoopMode.defaultRunLoopMode)


来源:https://stackoverflow.com/questions/8409656/how-to-correctly-stop-and-resume-a-cadisplaylink

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!