等待GCD异步在新代码之前停止

时间:2012-12-27 23:40:33

标签: ios grand-central-dispatch

我有一个GCD背景。我有一个按钮,按下时我希望它在GCD完成时加载一个加载等待屏幕,然后执行该按钮上的其余代码。随附的是样本。

我的工作不起作用,我基本上想说,只要完成GCD就等待,并在此期间加载等待的消息,完成后继续编码。

谢谢

- (IBAction)btnTapped:(id)sender
{
    shouldCancel=NO;
    dispatch_queue_t existingQueque = dispatch_get_main_queue();//finds the current GCD, the one I created in a different method
    dispatch_group_t group =dispatch_group_create();

    dispatch_group_async(group, existingQueque, ^
    {
        dispatch_group_wait(group, DISPATCH_TIME_FOREVER);//does not work, I guess group can't be created here.
        [self performSelectorOnMainThread:@selector(showWaitViewWithMessage:) withObject:@"Loading" waitUntilDone:YES];//load this until GCD queque done

        [self performSelector:@selector(performSearch) withObject:nil afterDelay:0];
    });    
}

2 个答案:

答案 0 :(得分:5)

有几点想法:

  1. 您建议dispatch_get_main_queue()“找到当前的GCD,我用不同的方法创建的GCD”。不,这只是获取主队列(如果您使用它,将阻止您的用户界面),而不是您通过dispatch_create_queue在其他地方创建的队列。 dispatch_get_main_queue()只是获取主要排队,当您的搜索发生时,您的用户界面将被屏蔽(例如UIActivityIndicatorView无法旋转,无论如何)。

  2. 如果你已经将一大堆任务发送到后台队列,如果你想等待所有任务完成,那就是当你使用dispatch_group_tdispatch_barrier时,鉴于你所展示的内容不需要(你只有一个调度操作),你就不需要去那里了。顺便说一下,如果您使用全局队列,则不建议使用障碍。

  3. 单个GCD后台任务的典型模式比您的问题建议的更简单。您(a)更新您的UI以说“加载”并显示UIActivityIndicatorView或类似的东西,因此用户有一个更丰富的用户体验,向他们展示应用正在处理某些事情; (b)在后台派遣搜查; (c)完成后,将UI更新发送回主队列。因此,典型的模式是:

    - (IBAction)btnTapped:(id)sender
    {
        dispatch_queue_t backgroundQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    
        // or, if you've already created you own background queue just use that here, 
        // or just create one here. But don't use dispatch_get_main_queue, as that 
        // won't use a background queue.
        //
        // dispatch_queue_t backgroundQueue = dispatch_queue_create("org.yourdomain.yourapp.search", NULL);
    
        [self showWaitViewWithMessage:@"Loading"];
    
        dispatch_async(backgroundQueue, ^{
            [self performSearch];             // do this in the background
            dispatch_async(dispatch_get_main_queue(), ^{
                [self updateUiAfterSearch];   // when done, dispatch UI update back to main queue
            });
        });
    
        // if you created a queue, remember to release it
        //
        // dispatch_release(backgroundQueue); 
    }
    
  4. 另外,在performSelectorOnMainThread中,我认为没有理由waitUntilDone。除非有一些令人信服的理由,否则不要等待。如上所述,根本不需要这个构造,只需要一个FYI。

  5. 顺便说一句,重要的是要知道许多服务器对给定客户端一次可以发出的并发请求数量施加限制。如果您可能正在发起多个请求(例如,用户点击按钮并且服务器响应缓慢),这允许它们同时运行。在这种情况下,值得追求NSOperationQueue,您可以在其中设置maxConcurrentOperationCount。如果您使用NSOperationQueue方法的块版本(例如addOperationWithBlock而不是GCD的dispatch_async),则代码可以采用相同的方式构建,但它可以限制背景的数量操作

    此外,NSOperationQueue提供了在操作之间轻松建立依赖关系的能力(例如,依赖于所有其他完成的完成NSOperation)。我可以概述一下,但是你发布的代码并不是必须的,所以除非你让我知道你想知道它会是什么样子,否则我会饶恕你。

答案 1 :(得分:1)

你必须保存你创建的队列,不要每次都创建它,如果你一次只想要一个,请使用串行队列


 @implementation DDAppDelegate {
     dispatch_queue_t queue;
 }

 - (void)applicationDidFinishLaunching:(NSNotification *)aNotification
 {
     [self do];
     [self performSelector:@selector(do) withObject:nil afterDelay:1];
 }

 - (void)do {
     if(!queue)
         queue = dispatch_queue_create("com.example.MyQueue", NULL);

     dispatch_async(queue, ^{
         //serialized
         NSLog(@"1");
         sleep(10);
     });
 }
 @end

如果您想要并发队列,请使用全局队列并调度dispatch_barync

@implementation DDAppDelegate

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
    [self do];
    [self performSelector:@selector(do) withObject:nil afterDelay:1];
}

- (void)do {
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);

    dispatch_barrier_async(queue, ^{
        //serialized
        NSLog(@"1");
        sleep(10);
    });
}