6

我正在开发一个具有高度异步设计的 iOS 应用程序。在某些情况下,单个概念上的“操作”可能会将许多子块排队,这些子块将异步执行并异步接收它们的响应(对远程服务器的调用)。这些子块中的任何一个都可能在错误状态下完成执行。如果任何子块中发生错误,则应取消任何其他子块,错误状态应向上渗透到父块,并且应执行父块的错误处理块。

我想知道在这样的环境中工作可能会推荐哪些设计模式和其他技巧?

我知道 GCD 的 dispatch_group_async 和 dispatch_group_wait 能力。这可能是这个应用程序设计中的一个缺陷,但我对 dispatch_group_async 的运气并不好,因为该组似乎对子块没有“粘性”。

提前致谢!

4

3 回答 3

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];
于 2012-07-31T19:34:43.933 回答
1

自发布此问题以来,我遇到的一种模式是使用信号量将异步操作更改为同步操作。这非常有用。这篇博客文章更详细地介绍了这个概念。

http://www.g8production.com/post/76942348764/wait-for-blocks-execution-using-a-dispatch-semaphore

于 2014-09-20T23:31:02.640 回答
-1

有很多方法可以在 cocoa 中实现异步行为。

GCD、NSOperationQueue、performSelectorAfterDelay,创建自己的线程。有适当的时间使用这些机制。在这里讨论太长了,但是您在帖子中提到的一些问题需要解决。

如果任何子块中发生错误,则应取消任何其他子块,错误状态应向上渗透到父块,并且应执行父块的错误处理块。

块不能将错误抛出堆栈。时期。

于 2012-08-08T03:17:37.160 回答