2012-07-31 403 views
6

我正在研究具有高度異步設計的iOS應用程序。有些情況下,一個概念性的「操作」可能排隊許多異步執行的子塊,並異步接收它們的響應(調用遠程服務器)。這些子塊中的任何一個都可以在錯誤狀態下完成執行。如果在任何子塊中發生錯誤,則應取消任何其他子塊,錯誤狀態應滲透至父項,並且應執行父項的錯誤處理塊。異步塊的推薦設計模式?

我想知道什麼樣的設計模式和其他技巧可能會被推薦在像這樣的環境中工作?

我知道GCD的dispatch_group_async和dispatch_group_wait功能。這可能是這個應用程序設計中的一個缺陷,但是我沒有使用dispatch_group_async的好運,因爲該組似乎對子塊沒有「粘性」。

在此先感謝!

回答

5

有一個WWDC視頻(2012年),可能會幫助你。它使用自定義的NSOperationQueue並將異步塊放在NSOperations內,以便您可以保留塊的句柄並取消剩餘的排隊塊。

一個想法是將錯誤處理的子塊調用處理NSOperationQueue的類中的主線程上的方法。然後課堂可以適當地取消休息。這樣子塊只需要知道他們自己的線程和主線程。下面是視頻

https://developer.apple.com/videos/wwdc/2012/

視頻被稱爲「iOS上構建併發用戶界面」的鏈接。相關部分主要在下半年,但您可能希望看到整個事情,因爲它將它放在上下文中很好。

編輯:

如果可能的話,我建議你在處理的嵌入式模塊,它包裝好聽在一起,這是我認爲你後的反應..

//Define an NSBlockOperation, and get weak reference to it 
NSBlockOperation *blockOp = [[NSBlockOperation alloc]init]; 
__weak NSBlockOperation *weakBlockOp = blockOp; 

//Define the block and add to the NSOperationQueue, when the view controller is popped 
//we can call -[NSOperationQueue cancelAllOperations] which will cancel all pending threaded ops 
[blockOp addExecutionBlock: ^{ 

    //Once a block is executing, will need to put manual checks to see if cancel flag has been set otherwise 
    //the operation will not be cancelled. The check is rather pointless in this example, but if the 
    //block contained multiple lines of long running code it would make sense to do this at safe points 
    if (![weakBlockOp isCancelled]) { 

     //substitute code in here, possibly use *synchronous* NSURLConnection to get 
     //what you need. This code will block the thread until the server response 
     //completes. Hence not executing the following block and keeping it on the 
     //queue. 
     __block NSData *temp; 
     response = [NSData dataWithContentsOfURL:[NSURL URLWithString:urlString]]; 

     [operationQueue addOperationWithBlock:^{ 
      if (error) { 
        dispatch_async(dispatch_get_main_queue(), ^{ 
         //Call selector on main thread to handle canceling 
         //Main thread can then use handle on NSOperationQueue 
         //to cancel the rest of the blocks 
        }); 
      else { 
       //Continue executing relevant code....  
      } 
     }]; 
    } 
}]; 
[operationQueue addOperation:blockOp]; 
+1

謝謝,我觀看了視頻。我想我所躊躇的是如何在等待異步響應的同時將操作基本上保存在隊列中?能夠利用NSOperationQueue會很方便。我之前在其他應用中使用過這個類,但之前我只有隊列處理出站請求 - 而不是響應處理。在這個應用程序中,操作不會完成,直到處理完響應並且任何關聯的子請求也完成。 – xyzzycoder 2012-08-09 02:42:22

+0

你可以把響應處理代碼放入一個嵌入塊嗎?我會更新我的答案 – 2012-08-09 09:11:37

+0

如果你在'NSOperation'世界,而不是'dispatch_async(dispatch_get_main_queue(),^ {});',爲什麼不''[[NSOperationQueue mainQueue] addOperationWithBlock:^ {}]; ?你得到的很好,但將GCD調用與「NSOperationQueue」調用混合起來感覺很奇怪。 – Rob 2013-01-02 22:28:37

-1

在可可中實現異步行爲的方法有很多。

GCD,NSOperationQueue,performSelectorAfterDelay,創建自己的線程。有適當的時候可以使用這些機制。這裏討論時間太長,但是你在帖子中提到的內容需要解決。

應該發生在任何兒童塊中的錯誤,任何其他的孩子塊應該被取消,錯誤狀態應該滲出到父,和父母的錯誤處理塊應該被執行。

塊不能拋出堆棧錯誤。期。

+0

謝謝。在這個應用程序中,我有一個與服務器的通信通道,並且客戶機/服務器操作是隱式串行的。我沒有試圖在堆棧上傳遞任何錯誤。 – xyzzycoder 2012-08-09 02:29:06

+0

所以你只需要一個異步調用 - 使用GCD,或者創建你自己的線程。 – 2012-08-09 02:31:10