2011-12-07 93 views
12

我想出了CADisplayLink的一个大问题。如何正确停止和恢复CADisplayLink?

我有最基本的EAGLLayer与OpenGL ES 1.1绘制一个旋转三角形进行测试。这需要一个运行循环方法在屏幕刷新率被调用,所以我开始喜欢这个runloop:

- (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; 
    } 
} 

当测试应用程序启动,我打电话-startRunloop。 当我点击屏幕时,我打电话给-stopRunloop。 当我再次点击时,我打电话给-startRunloop。等等。乒乓。

我测量在20秒内调用-drawFrame方法的次数,并NSLog它。

  • 第一次启动/停止循环始终以100%执行。我得到最大帧速率。

  • 所有SUBSEQUENT启动/停止周期仅显示约80%的性能。我得到了更小的帧速率。但是:总是几乎完全相同,+/- 2帧。即使经过50次以上的启动/停止循环,也不会有进一步降级的趋势。

结论:创建CADisplayLink像我上面做的很好,直到它失效或暂停。之后,任何新的CADisplayLink都不能很好地运行。即使它的创建方式与之前完全一样,仍然是新的。如果通过使用YES/NO调用-setPaused:方法来暂停/恢复它,情况也是如此。

我已经确定Allocations和VM Tracker工具没有内存管理问题。我也检查过,CADisplayLink的-validate方法真的被调用。

设备上的iOS 4.0(iPhone 4)。

这是为什么?我错过了什么吗?

+0

这听起来像一个错误。我认为你需要向苹果提交一份错误报告。 –

+0

我有同样的问题。我不需要DisplayLink始终运行,但看起来我没有选择。所以现在我只是在处理程序选择器中使用标志而不是使用isPaused。 –

回答

1

您可以为每次开始调用创建一个新的显示链接实例。你有没有尝试过重复使用同一个实例?

此外,你总是可以暂停显示链接。

5

我使用

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

看看它是否适合你

5

我想你,你真正想要的是简单地暂停和取消暂停您的显示链接。

- (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; 
} 
0

在斯威夫特试试这个,

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