2012-07-31 208 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