2008-12-16 153 views
26

我正在設計應用程序的階段,該應用程序將使用REST Web服務,並且在使用異步與同步與線程之間存在困難。這是場景。iPhone應用程序中的異步與同步與線程

假設您有三種深入的選擇,每種都有自己的基於REST的資源。我可以用同步請求延遲加載每個請求,但這會阻止用戶界面,並阻止用戶在檢索數據時碰到後退導航按鈕。這種情況幾乎適用於,除了,當你的應用程序需要登錄屏幕。由於這個原因,我看不出有任何理由使用同步HTTP請求。唯一有意義的是讓工作線程發出同步請求,並在請求完成時通知主線程。這將阻止該塊。接下來的問題就是在代碼中標記代碼,看看哪些代碼有更多開銷,線程同步請求或異步請求。

異步請求的問題是您需要設置智能通知或委託系統,因爲您可以在任何給定時間對多個資源發生多個請求。他們的另一個問題是如果我有一個類,比如說一個處理所有數據的單例,我不能在getter方法中使用異步請求。這意味着下面的不會去:

- (NSArray *)users { 
    if(users == nil) 
     users = do_async_request // NO GOOD 

    return users; 
} 

,而以下幾點:

- (NSArray *)users { 
    if(users == nil) 
     users == do_sync_request // OK. 

    return users; 
} 

您也可以享有優先權。我的意思是優先考慮的是,如果您查看iPhone上的Apple的Mail應用程序,您會注意到他們首先會刪除整個POP/IMAP樹,然後再次請求檢索郵件的前兩行(缺省值)。

我想我的問題給你的專家是這樣的。何時使用異步,同步,線程 - 以及何時在線程中使用異步/同步?當異步請求完成時,您已經設置了什麼樣的委派系統來知道該怎麼做?您是否優先處理異步請求?

對於這個太常見的問題,有一個解決方案的色域。破解一些東西很簡單。問題是,我不想破解,我想要一些簡單易維護的東西。

回答

7

我不認爲有一個「正確的」答案。看起來你明白所涉及的妥協,你只需要圍繞這些做出設計。

一些額外的隨機點:有時您的應用程序會強制使用特定的方法。例如,許多便利(即同步)方法將不允許認證。對我而言,這意味着我做出了決定。

對於Yummy我結束了而不是使用線程。我使我所有的網絡調用都是異步的,並使用默認的XML解析器(使用回調函數)。由於它全部由事件驅動,每個單元都很小,因此GUI可以很流暢,而且不會增加線程的複雜性。

我使用狀態機來找出爲什麼我得到一個特定的響應,以及一個隊列,以便我只需要在任何給定時間「在飛行中」進行單個操作。對大多數請求都有明確的順序,所以我不需要優先系統。

網絡代碼是我的應用程序中最複雜的,並且花費很長時間才能使工作強度大大降低!

+0

斯蒂芬,我認爲一個狀態機和隊列將幫助我噸。我假設你在任何地方都沒有例子? – Coocoo4Cocoa 2008-12-16 16:18:29

+0

「狀態機」是對它進行表述的一種相當宏偉的方式......它是一些布爾和一些switch語句。沒有什麼非常聰明的,但我發現預先繪製在一張紙上是有用的。隊列只是一個NSMutableArray。 – 2008-12-16 22:46:14

1

我個人看看正在做什麼,我會通常使用asyc請求來確保UI不會阻止,但是,我可能會在請求過程中禁用我的應用程序的UI。

一個最好的例子就是我用「搜索」按鈕構建的應用程序。一旦搜索被觸發爲異步請求,我會禁用按鈕,直到響應回來,有效地限制用戶產生第二個asyc請求的能力。

這樣做,至少我可以防止對優先事項的需求,只有在您可以以簡單的方式進行操作時才允許這樣做,並且一次只限制一個操作。

1

我會建議異步的方式,沒問題。然後,只在需要時加載信息,並使用委託系統將該信息提供給正確的對象。

您不想阻止用戶界面。永遠。並且異步加載信息允許您更好地控制發生的事情,以便在需要時可以發出錯誤消息。

-1

爲什麼你不能使用異步請求,就像這樣:

- (NSArray *)users { 
    if(users == nil && !didLaunchRequestAlready) 
     users = do_async_request // Looks good to me 
    return users; 
} 

異步絕對是唯一的選擇 - 唯一真正的問題是,如果你想開始使用單獨的線程,或者如果你想只使用異步呼叫。從那裏開始,如果你真的需要管理線程。

+0

你的return語句會在異步請求完成之前執行,所以你不會得到結果,只是nil。 – 2009-08-15 14:41:19

+0

@Danny:你可能想要設置一個委託方法/通知,它會表示請求已完成,並填充UITableView或其他內容。 – sebnow 2010-08-15 09:31:00

8

我不打折異步委託調用,但我通常最終使用同步請求的線程工人類。從長遠來看,我發現擁有一個定義良好的線程化API更容易,而不是用管理異步方法之間狀態的代碼填充控制器。你甚至可以在你的工作線程中進行異步操作,儘管通常使用同步方法比較容易,除非它們不支持你需要使用的功能。當然,所有這些都取決於具體情況,我可以想到很多情況下,簡單地使用異步方法將是最佳路線。

絕對考慮NSOperationQueue,如果你走這條路線;它大大簡化了創建多個工作線程,並且還支持操作之間的優先級和依賴關係。現在在10.5上有一些問題,但我沒有聽說iPhone上有任何問題。

1

只是想:如果你想使用iPhone的單元測試框架,你可能想要有同步功能,因爲這可能會使測試更容易編寫。

但是,您的某些API可能無法同步工作,因此您需要將它們轉換爲同步任務。如果執行單元測試的代碼在其自己的線程中運行,那麼可以編寫一個包裝,等待異步任務完成。

要做到這一點,您需要使用信號量:您的包裝函數啓動異步操作,然後使用信號量來阻止自己(即將自己置於睡眠狀態)。指示異步事件結束的回調釋放信號量,以便睡眠包裝線程可以繼續並返回。

0

我會同步使用dispatch_async。這樣,你有沒有代表/ NSNotifications的優勢,它是非阻塞

- (NSArray *)users { 
    if(users == nil) { 
     users = do_sync_request(); 
    } 

    return users; 
} 

// now when calling the users method, do this 

- (NSArray *)getUsers { 
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 
      NSArray *users = [self users]; 
      dispatch_sync(dispatch_get_main_queue(), ^{ 
       return users; 
      } 
    } 
}