2012-07-15 59 views
6

我正在開發iPad應用程序,目前我正在努力尋找多線程的最佳方法。讓我來說明這一點有一個簡單的例子:
我有2子視圖,目錄選擇器,並在選定的目錄中的所有圖像的縮略圖畫廊的視圖。由於「下載」並生成這些縮略圖可能需要很長時間,因此我需要多線程,因此視圖的交互和更新不會被阻止。目標C中的最佳多線程方法?

這是我已經嘗試過:
[自performSelectorInBackground:@selector(displayThumbnails :) withObject:currentFolder]。
這工作得很好,因爲用戶交互並沒有得到阻止,但它草草收場,當用戶在另一個文件夾水龍頭,而第一個文件夾仍在加載失敗。兩個線程試圖訪問相同的視圖和變量,這會導致彼此正確執行。當用戶點擊另一個文件夾時,當前正在加載的文件夾的displayThumbnails應該中止。我沒有找到任何辦法做到這一點..

NSThreads
我試過,但幾乎同樣的問題掙扎與第一種方法,我沒有找到一個(簡單)的方式來取消持續的方法。 (是的,我知道約[aThread cancel],但沒有找到'恢復'線程的方式)。也許我應該繼承NSThread並實現我自己的isRunning等方法?但是沒有更好的辦法,或者我忽略了第三種(甚至是第四種和第五種)選項嗎?

我認爲這是一個相當簡單的例子,我認爲沒有繼承NSThread也許有更好的解決方案。那麼,你會怎麼做?你的意見請!

+4

顯然我不能作出答案,只讀「GCD」 – JustSid 2012-07-15 22:14:08

+4

你完全錯了。認真。 – puzzle 2012-07-15 22:23:52

+0

請參閱[這裏](https://developer.apple.com/library/ios/#documentation/General/Conceptual/ConcurrencyProgrammingGuide/OperationQueues/OperationQueues.html%23//apple_ref/doc/uid/TP40008091-CH102-SW2)爲什麼GCD如此酷:)或者更好,請觀看WWDC會議之一:) 關於您的原始問題:無論您是使用線程,GCD還是NSOperationQueue,取消或暫停都有多種方式。你可以睡覺,暫停,等待一個鎖,完全取消等等。我認爲NSOperationQueue現在對你來說會是一個很好的解決方案,因爲它會自動引導你到一個合理的實現。 – puzzle 2012-07-15 22:32:32

回答

6

NSOperationQueue應該爲這項任務工作。

另一種選擇是普通的GCD,但是,如果你從未使用過NSOperationQueue,NSOperationQueue可能是更好的選擇,因爲它幾乎可以自動引導你以「正確的方式」實現,具有明顯的取消方法,等

5

你想使用併發NSOperations在後臺下載和處理圖像。這些將由NSOperationsQueue管理。實質上,這些操作將被配置爲每個操作獲取一個圖像,處理該圖像,將其保存在文件系統中,然後將消息發送回主圖像可用的主線程中的主應用程序。

在github上有幾個項目,你可以看看如何做到這一點 - 只需使用「併發」或「NSOperation」搜索github。

iOS對於做後臺工作非常好。大中央調度(GCD)和塊,但這些不讓你有一個使用委託回調的對象 - 因此NSOperation。

所以你需要閱讀塊,GCD,然後看看一些開源的併發NSOperations代碼。使用Concurrent NSOperations並不像使用塊那麼簡單。

0

如果我有這個問題,我可能會去像這樣的方法:

  • 一個單獨的線程將加載圖像,並導致主線程來顯示結果(我不是一個對GUI對象有線程混亂的大粉絲)

  • 當一個新的目錄被請求時......好吧,這取決於你想如何管理事情。基本上,一個標準的隊列結構(條件變量和數組)可以用於主線程,通過傳遞路徑名來告訴線程「這個目錄將被需要」;線程將檢查隊列,即使它正在加載圖像(如在每個圖像之後),並且在出現時切換到新目錄

  • 您可以創建一個保持所有狀態的目錄讀取器對象,並且將該路徑索引存儲到字典中。當請求一個新目錄時,首先檢查該字典,並且只有在該目錄沒有時才創建一個新對象。這樣一來,部分加載的目錄會一直存在,直到它們再次被需要,並且可以繼續加載而不必從頭開始。

的僞代碼螺紋:

while (forever) 
    new element = nil 
    if we have an active directory loader 
     tell directory loader to load one image 
     if false then make directory loader inactive 
     lock queue condition 
     if queue has elements 
      new element = retrieve LAST element (we aren't interested in the others) 
      empty queue 
      unlock with status "empty" 
     else 
      unlock queue 
    else 
     lock queue on condition "has elements" 
     new element = retrieve last element 
     empty queue 
     unlock with status "empty" 
    if new element != nil 
     if directory loader for new path does not exist 
      setup new directory loader for new path 
      store in dictionary 
      make it the "active" one 
     else 
      make the current one the "active" 

至於目錄加載器,它可能是這個樣子:

read one image: 
    if there are still images to read: 
     read, process and store one 
     return true 
    else 
     performSelectorOnMainThread with an "update GUI" method and the image list as parameter 
     return false; 

這僅僅是一個速寫;線程中存在一些代碼重複,而且我編寫它的方式只會在所有圖像被讀取後更新GUI,而不是在我們讀取它們時出現。您必須複製當前的圖像列表,或者添加同步,如果你想這樣做。