等待条件继续 [英] Waiting for condition to continue

查看:93
本文介绍了等待条件继续的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个方法,我添加到我创建的GCD队列(所以它是一个串行队列),然后运行它异步。从该代码块中,我调度到主队列,当分派到主队列的代码块完成时,我将一个BOOL标志设置为YES,这样我进一步在我的代码中可以检查这个条件是否是YES然后我可以继续下一个方法。下面是代码:

  dispatch_queue_t queue = dispatch_queue_create(ProcessSerialQueue,0); 

dispatch_async(queue,^ {

Singleton * s = [Singleton sharedInstance];

dispatch_sync(dispatch_get_main_queue(),^ {
[s processWithCompletionBlock:^ {

// Process is complete
processComplete = YES;
}];
});;
});

while(!processComplete){

NSLog(@Waiting);
}

NSLog(@准备下一步);

但是这不起作用,因为dispatch_sync永远不能在主队列上运行代码。这是因为我在主队列上运行一个while循环(使其忙碌)?



但是如果我把while循环的实现改为: p>

  while(!processComplete){

NSLog(@Waiting)
NSDate * date = [NSDate distantFuture];
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:date];
}

它没有毛刺。这是一个可接受的解决方案吗?我可以用任何其他首选方式吗?什么样的神奇的东西 NSRunLoop 做?我需要更好地理解这一点。

解决方案

主线程的NSRunLoop作业的一部分是运行任何在主线程排队的块。通过在while循环中旋转,你可以防止runloop进行,所以除非你显式地让循环自己运行,否则排队的块永远不会运行。



Runloops是Cocoa的基本部分,以及文档是相当不错,所以我建议阅读它。



d避免手动调用runloop。



但是,有一个更好的方式来处理这个。将方法拆分为-process和-didProcess方法。使用-process方法启动异步操作,完成后,从完成块调用-didProcess。如果您需要将变量从一个方法传递给另一个方法,您可以将它们作为参数传递给-didProcess方法。



例如:

  dispatch_queue_t queue = dispatch_queue_create(ProcessSerialQueue,0); 

dispatch_async(queue,^ {
Singleton * s = [Singleton sharedInstance];

dispatch_sync(dispatch_get_main_queue(),^ {
[processWithCompletionBlock :^ {
[self didProcess];
}];
});
});

你也可以考虑让你的singleton拥有dispatch队列并使它负责处理dispatch_async的东西,



例如:

pre> [[Singleton sharedInstance] processAyncWithCompletionBlock:^ {
NSLog(@准备下一步...);
[self didProcess];
}];


I have a method that I add to a GCD queue that I have created (so it's a serial queue) and then run it async. From within that block of code I make a dispatch to the main queue, when that block of code dispatched to the main queue is complete I set a BOOL flag to YES, so that I further down in my code can check if this condition is YES then I can continue to the next method. Here is the code in short:

dispatch_queue_t queue = dispatch_queue_create("ProcessSerialQueue", 0);

dispatch_async(queue, ^{

        Singleton *s = [Singleton sharedInstance];

        dispatch_sync(dispatch_get_main_queue(), ^{
            [s processWithCompletionBlock:^{

                // Process is complete
                processComplete = YES;
            }];
        });
});

while (!processComplete) {

        NSLog(@"Waiting");
}

NSLog(@"Ready for next step");

However this does not work, because dispatch_sync is never able to run the code on the main queue. Is this because I'm running a while loop on the main queue (rendering it busy)?

However if I change the implementation of the while loop to this:

while (!processComplete) {

        NSLog(@"Waiting")
        NSDate *date = [NSDate distantFuture];
        [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:date];
}

It works without a glitch. Is this an acceptable solution for this scenario? Can I do it any other preferred way? What kind of magic stuff does NSRunLoop do? I need to understand this better.

解决方案

Part of the main thread's NSRunLoop job is to run any blocks queued on the main thread. By spinning in a while-loop, you're preventing the runloop from progressing, so the queued blocks are never run unless you explicitly make the loop run yourself.

Runloops are a fundemental part of Cocoa, and the documentation is pretty good, so I'd reccommend reading it.

As a rule, I'd avoid manually invoking the runloop as you're doing. You'll waste memory and make make things complicated very quickly if you have multiple manual invocations running on top of one another.

However, there is a much better way of doing this. Split your method into a -process and a -didProcess method. Start the async operation with your -process method, and when it completes, call -didProcess from the completion block. If you need to pass variables from one method to the other, you can pass them as arguments to your -didProcess method.

Eg:

dispatch_queue_t queue = dispatch_queue_create("ProcessSerialQueue", 0);

dispatch_async(queue, ^{
        Singleton *s = [Singleton sharedInstance];

        dispatch_sync(dispatch_get_main_queue(), ^{
            [s processWithCompletionBlock:^{
                [self didProcess];
            }];
        });
});

You might also consider making your singleton own the dispatch queue and make it responsible for handling the dispatch_async stuff, as it'll save on all those nasty embedded blocks if you're always using it asynchronously.

Eg:

[[Singleton sharedInstance] processAyncWithCompletionBlock:^{
   NSLog(@"Ready for next step...");
   [self didProcess];
}];

这篇关于等待条件继续的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆