我正在开发一款具有高度异步设计的iOS应用。在某些情况下,单个概念性“操作”可能会排队许多子块,这些子块将异步执行并异步接收它们的响应(调用远程服务器)。这些子块中的任何一个都可以在错误状态下完成执行。如果在任何子块中发生错误,则应取消任何其他子块,错误状态应该渗透到父级,并且应该执行父级的错误处理块。
我想知道在这样的环境中可能会推荐哪些设计模式和其他技巧?
我知道GCD的dispatch_group_async和dispatch_group_wait功能。这可能是这个应用程序设计中的一个缺陷,但我对dispatch_group_async没有好运,因为该组似乎对子块没有“粘性”。
提前致谢!
答案 0 :(得分: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 :(得分:1)
自发布此问题以来,我遇到的一种模式是使用信号量将异步操作更改为同步操作。这非常有用。这篇博文更详细地介绍了这个概念。
http://www.g8production.com/post/76942348764/wait-for-blocks-execution-using-a-dispatch-semaphore
答案 2 :(得分:-1)
有许多方法可以在cocoa中实现异步行为。
GCD,NSOperationQueue,performSelectorAfterDelay,创建自己的线程。有适当的时间使用这些机制。在这里讨论的时间太长了,但你在帖子中提到的内容需要解决。
如果在任何子块中发生错误,则应取消任何其他子块,错误状态应该被渗透到父级,并且应该执行父级的错误处理块。
阻止无法在堆栈中抛出错误。期。