2012-06-04 39 views
1

我想了解事情如何工作的併發編程和調用setNeedsDisplay。我基本上有三個對象。瞭解setNeedsDisplay/drawRect與塊

Main View - container with different UIView objects, the main one being a UIScrollView 
Small Map View - a small UIView that draws a miniature version of one of the other UIView items on screem 
Processor - a delegate of the Main View that calculates what's on screen and calls the Main View back with what's in view. 

所以,這是怎麼回事的一個簡單的例子是用戶觸摸了滾動,然後處理器更新有什麼考慮到滾動視圖(如計算座標,中心點等)爲此,它使用塊和不它是異步的。然後這將通知發佈到MainView對象。

當的MainView收到通知,它只是調用

[smallMap setNeedsDisplay]; // example 1 

我把解決這個調用一些記錄,我也看到它被調用的時候了。但是,該函數的drawRect:不會立即被調用。它會在2秒左右後被調用。

我記得讀到setNeedsDisplay只是標記重繪的視圖發生在運行循環的下一個事件。

但如果我添加此代碼來代替:

// example 2 
dispatch_async(dispatch_get_main_queue(), ^{ 
    [smallMap setNeedsDisplay];   
    }); 

我的觀點被重繪的時候了。

我想我爲什麼要問主要事件循環調用setNeedsDisplay來立即重繪一些東西感到困惑。就像在例子1中,我通過調用setNeedsDisplay,是在後臺完成的,或者是什麼,這就是爲什麼它不會立即重繪的原因?我試圖理解幕後發生的變化,所以我知道將來要尋找什麼。就像我應該讓所有需要立即重新繪製的示例2類似的電話一樣嗎?還是因爲我正在異步處理我的數據,我需要然後請求主隊列?謝謝!

回答

2

我的猜測是1 2的東西:

你是在一個單獨的線程運行時調用從單獨的線程,而不是使用performSelectorOnMainThread或GCD調用,調用在主線程的代碼你的MainView方法的代碼。因此,您對setNeedsDisplay的調用實際上是在後臺線程上進行的,這是另一個海報所說的禁止線程。

第二種可能性是您的MainView代碼在主線程上運行,但它忙於做耗時的處理,或等待同步調用另一個線程完成,並且不處理事件循環。

您可以通過在調用setNeedsDisplay時設置斷點並查看調試器中的調用跟蹤來查看它運行的線程,從而排除第一種可能性。

找出第二種可能性需要多一點工作。您可能需要深入研究儀器。

2

setNeedsDisplay是一個UIKIT API調用,必須從應用程序的主線程調用,也稱爲UI線程。這就是爲什麼在後臺線程中調用它並沒有立竿見影的效果,並將其安排在主隊列中會產生直接影響。

有關更詳細的解答,請參閱此相關問題https://stackoverflow.com/a/6988115/172690

+0

這是真的,但不適用於這個問題。他正在使用dispatch_async,但分派到主隊列,這應該工作得很好。 – Jiri

+1

錯誤,真的嗎?我正在閱讀的是他的代碼(請參見示例1)不工作,除非他將其發送到主線程(示例2)。你聲明使用主隊列使用dispatch_async是好的,我同意這一點。問題是爲什麼,而且我想我也沒有回答,如果我也困惑別人。抱歉。 –

+0

我理解問題的方式是示例1在主隊列上調用,示例2在另一個隊列上調用。然後,UIKit調用在兩種情況下都可以在主隊列上運行,這是可以的。我可能誤解了,對不起。 – Jiri