3

说我要实现像这样的模式:执行同步操作

a = some array I download from the internet 
b = manipulate a somehow (long operation) 
c = first object of b 

这些显然需要被同步调用,这是造成在目的C.我的问题,我读过有关NSOperationQueue和GCD,我不太了解它们,或者在这里适合。有人可以提出一个解决方案吗?我知道我也可以使用performSelector:@selector(sel)WaitUntilDone,但这对于较大的操作似乎并不高效。

回答

5

因此,创建一个串行调度队列,将所有工作(每个都在一个块中)转储,最后一个块在主队列上发回一个方法,告诉控制类工作完成。

这是迄今为止最完美的体系结构。

2

我很高兴你的问题得到解答。一对夫妇的补充意见:

  1. 在您的术语A小调细化,但我假设你希望异步运行这些任务(即不阻塞主队列和冻结用户界面),但你希望这些操作以串行方式进行(即,每个人在开始下一个任务之前都将等待前一步完成)。

  2. 最简单的方法,之前我潜入串行队列,是刚做这三个在一个单一的派遣任务:

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 
        [self doDownloadSynchronously]; 
        [self manipulateResultOfDownload]; 
        [self doSomethingWithFirstObject]; 
    }); 
    

    正如你所看到的,因为这是所有正在运行的这三个单任务你可以真正将它分派给任何后台队列(在上面,这是全局后台队列之一),但是因为你在给定的分派块内完成了这些,所以这三个步骤将按顺序,一个之后。

    请注意,尽管创建同步网络请求通常是不明智的,但只要您在后台队列上执行此操作,问题就不会那么严重(尽管您可能希望创建一个基于操作的网络请求,如下面所讨论的那样#5如果你想享受取消正在进行的网络请求的能力)。

  3. 如果您确实需要分别调度这三个任务,那么只需创建您自己的专用串行队列。默认情况下,当你创建自己的自定义调度队列,它是一个串行队列,如:

    dispatch_queue_t queue = dispatch_queue_create("com.company.app.queuename", 0); 
    

    可以安排这三个任务:

    dispatch_async(queue, ^{ 
        [self doDownloadSynchronously]; 
    }); 
    
    dispatch_async(queue, ^{ 
        [self manipulateResultOfDownload]; 
    }); 
    
    dispatch_async(queue, ^{ 
        [self doSomethingWithFirstObject]; 
    }); 
    
  4. 操作队列的做法是一样容易,但默认情况下,操作队列是并发的,所以如果我们希望它是一个串行队列,我们​​必须指定不存在并发操作(即最大并发操作数为1):

    NSOperationQueue *queue = [[NSOperationQueue alloc] init]; 
    queue.maxConcurrentOperationCount = 1; 
    
    [queue addOperationWithBlock:^{ 
        [self doDownloadSynchronously]; 
    }]; 
    
    [queue addOperationWithBlock:^{ 
        [self manipulateResultOfDownload]; 
    }]; 
    
    [queue addOperationWithBlock:^{ 
        [self doSomethingWithFirstObject]; 
    }]; 
    

    这引出了你为什么可能在GCD方法中使用操作队列方法的问题。主要原因是,如果您需要取消操作的能力(例如,如果用户放弃启动异步操作的视图控制器,您可能会停止操作),操作队列提供了取消操作的能力,但它更麻烦在GCD任务中这样做。

  5. 在我看来,这里唯一棘手/微妙的问题是,您希望如何同步执行网络操作。您可以使用NSURLConnection分类方法sendSynchronousRequest或仅使用dataWithContentsOfURL从服务器获取NSData。使用这些类型的同步网络请求存在限制(例如,一旦启动请求就无法取消请求),所以我们很多人都会使用基于NSOperation的网络请求。

    这样做是正确的可能是超出你的问题的范围,所以我可能会建议您可以考虑使用AFNetworking创建它,你可以在上述溶液#4集成了一个基于操作的网络请求,消除急需的编程如果你自己做了NSOperation的网络操作。

  6. 要记住的主要原因是,当您在后台队列上运行这类代码时,当您需要执行UI更新(或更新模型)时,这些代码必须返回到主队列中,不是背景排队。因此,如果做一个GCD的实现,你会怎么做:

    dispatch_async(queue, ^{ 
        [self doSomethingWithFirstObject]; 
    
        dispatch_async(dispatch_get_main_queue(),^{ 
         // update your UI here 
        }); 
    }); 
    

    等效NSOperationQueue翻译是:

    [queue addOperationWithBlock:^{ 
        [self doSomethingWithFirstObject]; 
    
        [[NSOperationQueue mainQueue] addOperationWithBlock:^{ 
         // update your UI here 
        }]; 
    }]; 
    

本质上引这些问题是Concurrency Programming Guide

有一吨的伟大的WWDC视频的话题,包括WWDC 2012的视频Asynchronous Design Patterns with Blocks, GCD, and XPCBuilding Concurrent User Interfaces on iOS和WWDC 2011视频Blocks and Grand Central Dispatch in PracticeMastering Grand Central Dispatch

+0

哇!非常感谢这个回应,我打算把它打印出来,然后带着我一起去咖啡店!对此,我真的非常感激!看起来像NSOperationQueue是超级简单易用! – JoshDG