2012-05-07 34 views
9

我正在使用CoreGraphics進行渲染的繪畫應用程序。我的問題是,爲了提高性能,我試圖將更新限制爲僅改變視圖的某些部分。爲此,我使用setNeedsDisplayInRect :,但有時視圖更新其整個內容,導致口吃。這在第三代iPad上尤其明顯,但它也在模擬器和iPad2中發生的程度較低。我正試圖消除這種行爲。setNeedsDisplayInRect:導致整個視圖更新

爲了展示這個問題,我使用Xcode中的模板創建了一個簡單的「單視圖」項目。創建了一個自定義的UIView子類,我將其設置爲xib文件中的視圖控制器視圖。

已將此添加的UIViewController:

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event 
{ 
    // Asks that the view refreshes a smal rectangle 
    [self.view setNeedsDisplayInRect:CGRectMake(10, 10, 20, 20)]; 
} 

已將此添加到MyView的(我的自定義視圖):

- (void)drawRect:(CGRect)rect 
{ 
    // Just log what is being updated 
    NSLog(@"%@", NSStringFromCGRect(rect)); 
} 

就是這樣。如果我在第三十臺iPa​​d(實際設備)上運行該應用程序,則日誌會顯示該視圖時常(如非常頻繁)重新繪製其本身的內容。這太令人沮喪了,我不知道

更新:這裏有一些日誌。它絕對顯示有時更新的全景。我試圖使它完全停止,但找不出如何...

2012-05-04 08:34:01.851 TestUpdateArea[45745:707] {{0, 0}, {320, 460}} 
2012-05-04 08:34:30.184 TestUpdateArea[45745:707] {{0, 0}, {320, 460}} 
2012-05-04 08:34:30.197 TestUpdateArea[45745:707] {{0, 0}, {320, 460}} 
2012-05-04 08:34:30.215 TestUpdateArea[45745:707] {{10, 10}, {20, 20}} 
2012-05-04 08:34:30.226 TestUpdateArea[45745:707] {{10, 10}, {20, 20}} 
2012-05-04 08:34:30.242 TestUpdateArea[45745:707] {{10, 10}, {20, 20}} 
2012-05-04 08:34:30.258 TestUpdateArea[45745:707] {{10, 10}, {20, 20}} 
2012-05-04 08:34:30.274 TestUpdateArea[45745:707] {{10, 10}, {20, 20}} 
2012-05-04 08:34:30.290 TestUpdateArea[45745:707] {{10, 10}, {20, 20}} 
2012-05-04 08:34:30.306 TestUpdateArea[45745:707] {{10, 10}, {20, 20}} 
2012-05-04 08:34:30.322 TestUpdateArea[45745:707] {{10, 10}, {20, 20}} 
2012-05-04 08:34:30.338 TestUpdateArea[45745:707] {{10, 10}, {20, 20}} 
2012-05-04 08:34:30.354 TestUpdateArea[45745:707] {{10, 10}, {20, 20}} 
2012-05-04 08:34:30.371 TestUpdateArea[45745:707] {{10, 10}, {20, 20}} 
2012-05-04 08:34:30.387 TestUpdateArea[45745:707] {{10, 10}, {20, 20}} 
2012-05-04 08:34:30.403 TestUpdateArea[45745:707] {{10, 10}, {20, 20}} 
2012-05-04 08:34:30.419 TestUpdateArea[45745:707] {{10, 10}, {20, 20}} 
2012-05-04 08:34:30.439 TestUpdateArea[45745:707] {{0, 0}, {320, 460}} 
2012-05-04 08:34:30.457 TestUpdateArea[45745:707] {{10, 10}, {20, 20}} 

另外,如果我停止10s以上左右,恢復動人,它肯定不會很一致:

2012-05-04 08:34:33.305 TestUpdateArea[45745:707] {{10, 10}, {20, 20}} 
2012-05-04 08:34:33.321 TestUpdateArea[45745:707] {{10, 10}, {20, 20}} 
2012-05-04 08:35:00.202 TestUpdateArea[45745:707] {{0, 0}, {320, 460}} 
2012-05-04 08:35:00.221 TestUpdateArea[45745:707] {{0, 0}, {320, 460}} 
2012-05-04 08:35:00.234 TestUpdateArea[45745:707] {{0, 0}, {320, 460}} 
2012-05-04 08:35:00.251 TestUpdateArea[45745:707] {{10, 10}, {20, 20}} 
+0

在我的情況,當drawRect在setNeedsDisplayInRect之後調用**第一次**時,rect是滿邊界(不要問我爲什麼),任何下一次調用它就是我在setNeedsDisplayInRect中指定爲參數的rect。您是否測試觸摸移動不止一次? –

+0

它直接發生在設備上。但是,如果您移動手指並等待約10秒或15秒,然後再次觸摸並移動,則可以在模擬器上進行操作。在iPad3設備上,即使在手指移動時也會發生。 Sooo討厭:) – mprivat

+0

我張貼@這一段時間回來(http://stackoverflow.com/questions/9299018/setneedsdisplayinrect-bug-in-ios5)。這似乎只是在第一個電話。我從來沒有找到一個原因/修復,只是繼續前進,因爲我不需要這樣的性能優化級別。你可以測試rect ==視圖大小而不是繪製?也許不是一種選擇。 –

回答

5

檢查這個蘋果document

他們說:

的,因爲的方式,iPhone/iPod的觸摸/ iPad的upda測試其屏幕,如果您撥打-setNeedsDisplayInRect:-setNeedsDisplay:,整個視圖將被重新繪製。

另外

UIView的每個被處理爲單獨的元件。當您通過調用-setNeedsDisplayInRect:-setNeedsDisplay:來請求重新部分或全部重繪時,整個視圖將被標記爲更新。

所以我認爲你需要使用子視圖來更新整個視圖的獨立矩形。

+1

這沒有意義。那麼採用這兩種方法會有什麼意義呢?爲什麼它只有時纔有效? – mprivat

+0

我讀了一些在iOS 5中的錯誤,你在iOS 4上嘗試過嗎? –

+0

它在iOS4中做到的程度要小得多。 – mprivat

0

我有一個類似的問題:即想通過調用setNeedsDisplayInRect只更新一個UIView的一部分:我傳遞了一個正確大小的有效CGRect(用斷點和日誌證明)。在iOS 4.2.1下(在我的iPhone 3G上),UIView保留其原始圖像,只更新由CGRect指定的部分,但在iOS 5.1下(在我的iPhone 4S上),整個UIView都以透明黑色重新繪製透明超越了我),CGRect指定的區域在後面正確繪製。它似乎是:蘋果的一個錯誤,他們沒有實現setNeedsDisplayInRect:正確,只是將它傳遞給setNeedsDisplay:;或者它是基於新的iOS如何處理與實際屏幕架構的交互的故意決定。無論哪種方式,看起來目前開發人員不得不承擔每次發生圖形更改時更新整個UIView的成本,或者使用一些iOS檢測並根據正在處理的iOS實施不同的屏幕繪製代碼。

我已經使用UIView屬性clearsContextBeforeDrawing(根據文檔應允許有針對性的繪製操作)進行了一些測試,但結果對於YES和NO都是相同的,所以它似乎是繪製代碼的實現。

至於是的CGRect更新過程中不正確的尺寸:它是被設置在其他地方之前,或之後,繪圖調用。我在調用setNeedsDisplayInRect之前設置了CGRect,然後在drawRect方法的最後幾行將其設置爲CGRectNull(這是因爲如果系統調用drawRect方法,我的代碼不會觸發)。回到你的代碼片段後,我可以看到它被內聯設置,這意味着它是一個重新繪製整個UIView的系統調用,因此CGRect爲什麼是整個視圖。我會繼續深入研究這個問題,但是我擔心,除非蘋果公開他們對setNeedsDisplayInRect的更改的推理:或者修復了明顯的錯誤,否則我們可能會考慮更新每個圖形的UIView的全部內容更新(可能會非常昂貴)。

+0

這是我所害怕的。我與蘋果公司一起打開了一張技術支持票,他們悄悄地關閉了它,並且把票成本記入了我的賬戶,卻沒有說一句話...... – mprivat

13

接受的答案是錯的(或至少是誤導)。

這裏的setNeedsDisplayInRect的一個簡單的代碼示例:工作作爲標榜:

http://charcoaldesign.co.uk/resources/chalkboard.zip

我懷疑蘋果文檔試圖解釋一個事實,即在iOS每個視圖後盾圖像被轉換成一個OpenGL紋理並且整個屏幕都是每幀重新合成的。這與您的代碼是否必須清除並重繪視圖的背景紋理的全部內容的問題截然不同。

通過使用setNeedsDisplayInRect:可以避免不幀之間改變(使用芯圖形和沒有硬件加速的)內容昂貴重繪。整個屏幕仍然會不分重繪,但這並不重要,因爲它的硬件由GPU加速,不像在drawRect中的代碼:

0

我沒有很多提供給我的設備,但我有很大的反正新聞!作爲一個多年來一直希望在iOS上使用此功能的人,我可以斷言iOS8.0 +會帶來這種功能。我試過兩個模擬器和設備8.0,8.1,8.2

我沒有,因爲iOS6的嘗試這樣做。所以我不確定它是否在iOS7中可用。也許別人可以證實。

請和我一起在無休止地歡呼setNeedsDisplayInRect:用作記錄!

相關問題