2

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

2 回答 2

5

几个想法:

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

  2. 如果您已将一大堆任务分派到后台队列,如果您想等待所有任务完成,那就是您使用dispatch_group_tor的时候dispatch_barrier,但鉴于您所显示的内容并不需要(您只有一个调度操作),你只是不需要去那里。顺便说一句,如果您使用全局队列,则不建议使用屏障。

  3. 单个 GCD 后台任务的典型模式比您的问题建议的更简单。您 (a) 更新您的 UI 以显示“正在加载”并显示 aUIActivityIndicatorView或类似的内容,以便用户拥有更丰富的 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。除非有令人信服的理由,否则不要等待。正如你在上面看到的,这个结构根本不需要,只是一个 FYI。

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

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

于 2012-12-28T05:19:16.540 回答
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_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);
    });
}
于 2012-12-27T23:48:10.603 回答