我有一种方法,可以将其添加到已创建的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(@"Ready for next step");


但是,这不起作用,因为dispatch_sync永远无法在主队列上运行代码。这是因为我在主队列上运行了while循环(使其处于繁忙状态)吗?

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

while (!processComplete) {

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


它可以正常工作。这是这种情况下可接受的解决方案吗?我可以采用其他任何首选方式吗? NSRunLoop做什么样的魔术?我需要更好地理解这一点。

最佳答案

主线程的NSRunLoop作业的一部分是运行在主线程上排队的所有块。通过在while循环中旋转,可以防止runloop进行,因此,除非您明确使循环自己运行,否则永远不会运行排队的块。

Runloop是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];
}];

关于objective-c - 等待条件继续,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/13824394/

10-14 21:46