2011-12-07 171 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)