等待条件继续

时间:2012-12-11 16:32:21

标签: objective-c cocoa grand-central-dispatch wait nsrunloop

我有一个方法,我添加到我创建的GCD队列(所以它是一个串行队列),然后运行它async。从该代码块中我调度到主队列,当调度到主队列的代码块完成时,我将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(@"Ready for next step");

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

但是,如果我将while循环的实现更改为:

while (!processComplete) {

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

它没有故障。对于这种情况,这是否可接受?我可以用其他任何首选方式吗? NSRunLoop做了什么样的神奇事情?我需要更好地理解这一点。

3 个答案:

答案 0 :(得分:2)

主线程的NSRunLoop作业的一部分是运行在主线程上排队的任何块。通过在while循环中旋转,您将阻止runloop进行,因此除非您明确地自行运行循环,否则排队的块永远不会运行。

Runloops是Cocoa的一个有趣的部分,documentation非常好,所以我推荐阅读它。

通常,我会避免在您执行时手动调用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(), ^{
            [s processWithCompletionBlock:^{
                [self didProcess];
            }];
        });
});

你也可以考虑让你的单身人士拥有调度队列并让它负责处理dispatch_async的东西,因为如果你总是异步地使用它,它将节省所有那些讨厌的嵌入式块。

例如:

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

答案 1 :(得分:1)

做类似你发布的内容很可能会冻结用户界面。而不是冻结所有内容,在完成块中调用“下一步”代码。

示例:

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

dispatch_async(queue, ^{

        Singleton *s = [Singleton sharedInstance];

        dispatch_async(dispatch_get_main_queue(), ^{
            [s processWithCompletionBlock:^{
                // Next step code
            }];
        });
});

答案 2 :(得分:-2)

不要创建类似于在块内等待值的循环,块中的变量是只读的,而是从块内部调用完成代码。

dispatch_async(queue, ^{
    Singleton *s = [Singelton sharedInstance];
    [s processWithCompletionBlock:^{
        //process is complete
        dispatch_sync(dispatch_get_main_queue(), ^{
            //do something on main queue....
            NSLog(@"Ready for next step");
        });
    }];
});
NSLog(@"waiting");