【问题标题】:wait for GCD async to stop before new code在新代码之前等待 GCD 异步停止
【发布时间】:2013-02-02 02:29:57
【问题描述】:

我有一个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];
    });    
}

【问题讨论】:

  • dispatch_get_main_queue 为您获取系统创建并在主线程上提供服务的主队列。它没有得到你自己创建的队列
  • 那我怎么说“是否有活动队列?如果有,请等到完成”
  • 你不能。如果您需要引用您创建的队列,则需要保留对队列的引用。
  • 同意。典型的解决方案是将创建的队列存储在 ivar 中并在代码中引用它。或者只使用dispatch_get_global_queue。

标签: ios grand-central-dispatch


【解决方案1】:

一些想法:

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

  2. 1234563已经显示不需要(您只有一个已调度的操作),您只是不需要去那里。顺便说一句,如果您使用全局队列,则不建议使用屏障。
  3. 单个 GCD 后台任务的典型模式比您的问题所暗示的要简单。您 (a) 更新您的 UI 以显示“正在加载”并显示 UIActivityIndicatorView 或类似的内容,以便用户拥有更丰富的 UX,向他们展示应用正在处理某事; (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。除非有令人信服的理由,否则不要等待。正如你在上面看到的,这个结构根本不需要,只是一个仅供参考。

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

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

【讨论】:

    【解决方案2】:

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


     @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_barrier_async

    @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);
        });
    }
    

    【讨论】:

    • 顺便说一句,我认为不建议在全局队列上使用用户屏障。如果您真的担心协调并发后台队列,请使用未记录的dispatch_create_queue 功能,让您创建并发队列,或者更好的是使用NSOperationQueue,它可以让您创建后台并发队列并通过dependencies 协调操作.
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-16
    • 1970-01-01
    • 1970-01-01
    • 2020-06-20
    • 1970-01-01
    • 2017-11-14
    相关资源
    最近更新 更多