【问题标题】:How to correctly stop and resume a CADisplayLink?如何正确停止和恢复 CADisplayLink?
【发布时间】:2011-12-07 02:22:46
【问题描述】:

我发现 CADisplayLink 存在一个大问题。

我有最基本的 EAGLLayer 和 OpenGL ES 1.1 绘制一个旋转三角形进行测试。这需要以屏幕刷新率调用运行循环方法,所以我这样启动运行循环:

- (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。等等。乒乓球。

我正在测量 -drawFrame 方法在 20 秒内被调用的频率,并 NSLog 它。

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

  • 所有后续启动/停止循环仅显示大约 80% 的性能。我得到一个明显更小的帧速率。但是:总是几乎完全相同,+/- 2 帧。即使在 50 个以上的启动/停止循环之后,也没有进一步退化的趋势。

结论:像我上面那样创建 CADisplayLink 没问题,直到它失效或暂停。之后,任何新的 CADisplayLink 都不再表现良好。即使它是新的并且以与以前完全相同的方式创建。如果我通过使用 YES / NO 调用 -setPaused: 方法来暂停/恢复它,情况也是如此。

我已通过 Allocations 和 VM Tracker Instruments 确保不存在内存管理问题。我还检查了 CADisplayLink 的 -invalidate 方法是否真的被调用了。

设备上的 iOS 4.0 (iPhone 4)。

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

【问题讨论】:

  • 这听起来像一个错误。我认为您需要向 Apple 提交错误报告。
  • 我也有同样的问题。我不需要一直运行 DisplayLink,但看起来我别无选择。所以现在我只是在处理程序选择器中使用标志而不是使用 isPaused。

标签: iphone ios performance cadisplaylink


【解决方案1】:

我认为您真正想要的只是暂停和取消暂停显示链接。

 - (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】:

    我正在使用

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

    看看它是否适合你

    【讨论】:

      【解决方案3】:

      对于 Swift 4.2

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

      【讨论】:

        【解决方案4】:

        每次启动调用都会创建一个新的显示链接实例。您是否尝试过仅重用同一个实例?

        另外,您可以随时暂停显示链接。

        【讨论】:

          【解决方案5】:

          在 Swift 中试试这个,

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

          【讨论】:

            【解决方案6】:

            已经很久了,但是对于像我这样仍然有这种问题的人,当你开始时:

            if displayLink == nil {
              displayLink = CADisplayLink(target: self, selector: #selector(yourTarget))
              displayLink?.add(to: .main, forMode: RunLoop.Mode.common)
            } else {
              displayLink?.isPaused = false
            }
            

            然后当你需要停下来时:

            displayLink?.isPaused = true
            displayLink?.invalidate()
            displayLink = nil
            

            【讨论】:

              猜你喜欢
              • 2021-11-11
              • 1970-01-01
              • 1970-01-01
              • 2013-05-29
              • 1970-01-01
              • 2014-04-13
              • 1970-01-01
              • 2013-05-29
              • 2017-03-25
              相关资源
              最近更新 更多