首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >如何等待有完成块的方法(全部在主线程上)?

如何等待有完成块的方法(全部在主线程上)?
EN

Stack Overflow用户
提问于 2013-07-29 17:18:00
回答 7查看 35.8K关注 0票数 20

我有以下(伪)代码:

代码语言:javascript
复制
- (void)testAbc
{
    [someThing retrieve:@"foo" completion:^
    {
        NSArray* names = @[@"John", @"Mary", @"Peter", @"Madalena"];
        for (NSString name in names)
        {
            [someObject lookupName:name completion:^(NSString* urlString)
            {
                // A. Something that takes a few seconds to complete.
            }];

            // B. Need to wait here until A is completed.
        }
    }];

    // C. Need to wait here until all iterations above have finished.
    STAssertTrue(...);
}

这段代码在主线程上运行,完成块A也在主线程上。

  • 如何在B处等待A完成?
  • 随后如何在C处等待外部完成块完成?
EN

回答 7

Stack Overflow用户

回答已采纳

发布于 2013-07-29 17:59:06

如果您的完成块也在主线程上被调用,则可能很难实现此,因为在执行完成块之前,您的方法需要返回。您应该将异步方法的实现更改为:

  1. 保持同步。

或者

  • 使用其他线程/队列来完成。然后,您可以使用Dispatch信号量来等待。您使用值0初始化一个信号量,然后在主线程上调用wait,并在完成时调用signal

在任何情况下,阻塞主线程在图形用户界面应用程序中是非常糟糕的想法,但这不是你问题的一部分。在测试、命令行工具或其他特殊情况下,可能需要阻塞主线程。在这种情况下,请进一步阅读:

如何在主线程上等待主线程回调:

有一种方法可以做到这一点,但可能会产生意想不到的后果。谨慎行事!

主线程是特殊的。它运行的是同时处理+[NSOperationQueue mainQueue]dispatch_get_main_queue()+[NSRunLoop mainRunLoop]。分派到这些队列的所有操作或块都将在主运行循环内执行。这意味着,这些方法可以采用任何方法来调度完成块,这在所有这些情况下都应该有效。这就是它:

代码语言:javascript
复制
__block BOOL isRunLoopNested = NO;
__block BOOL isOperationCompleted = NO;
NSLog(@"Start");
[self performOperationWithCompletionOnMainQueue:^{
    NSLog(@"Completed!");
    isOperationCompleted = YES;
    if (isRunLoopNested) {
        CFRunLoopStop(CFRunLoopGetCurrent()); // CFRunLoopRun() returns
    }
}];
if ( ! isOperationCompleted) {
    isRunLoopNested = YES;
    NSLog(@"Waiting...");
    CFRunLoopRun(); // Magic!
    isRunLoopNested = NO;
}
NSLog(@"Continue");

这两个布尔值是为了确保块立即同步完成的情况下的一致性。

如果-performOperationWithCompletionOnMainQueue:asynchronous,,则输出将为:

启动

等待..。

完成!

继续

如果该方法为synchronous,,则输出将为:

启动

完成!

继续

什么是魔法?调用CFRunLoopRun()不会立即返回,只有在调用CFRunLoopStop()时才会返回。此代码位于主RunLoop上,因此再次运行主RunLoop将恢复所有调度块、计时器、套接字等的执行。

Warning:可能的问题是,所有其他计划的计时器和块将同时执行。此外,如果从不调用完成块,您的代码将永远不会到达Continue日志。

您可以将此逻辑包装在一个对象中,这样可以更容易地重复使用此模式:

代码语言:javascript
复制
@interface MYRunLoopSemaphore : NSObject

- (BOOL)wait;
- (BOOL)signal;

@end

因此,代码将简化为:

代码语言:javascript
复制
MYRunLoopSemaphore *semaphore = [MYRunLoopSemaphore new];
[self performOperationWithCompletionOnMainQueue:^{
    [semaphore signal];
}];
[semaphore wait];
票数 22
EN

Stack Overflow用户

发布于 2013-10-29 15:45:15

我认为Mike Ash (http://www.mikeash.com/pyblog/friday-qa-2013-08-16-lets-build-dispatch-groups.html的答案就是“等待几个线程完成,然后在所有线程完成后再做一些事情”。更好的是,您甚至可以使用分派组同步或非同步地等待。

从Mike Ash的博客中复制并修改了一个简短的例子:

代码语言:javascript
复制
    dispatch_group_t group = dispatch_group_create();

    for(int i = 0; i < 100; i++)
    {
        dispatch_group_enter(group);
        DoAsyncWorkWithCompletionBlock(^{
            // Async work has been completed, this must be executed on a different thread than the main thread

            dispatch_group_leave(group);
        });
    }

dispatch_group_wait(group, DISPATCH_TIME_FOREVER);

或者,您可以-同步等待并在所有块完成时执行操作,而不是dispatch_group_wait:

代码语言:javascript
复制
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
    UpdateUI();
});
票数 3
EN

Stack Overflow用户

发布于 2013-07-29 17:27:00

代码语言:javascript
复制
int i = 0;
//the below code goes instead of for loop
NSString *name = [names objectAtIndex:i];

[someObject lookupName:name completion:^(NSString* urlString)
{
    // A. Something that takes a few seconds to complete.
    // B.
    i+= 1;
    [self doSomethingWithObjectInArray:names atIndex:i];


}];




/* add this method to your class */
-(void)doSomethingWithObjectInArray:(NSArray*)names atIndex:(int)i {
    if (i == names.count) {
        // C.
    }
    else {
        NSString *nextName = [names objectAtIndex:i];
        [someObject lookupName:nextName completion:^(NSString* urlString)
        {
            // A. Something that takes a few seconds to complete.
            // B.
            [self doSomethingWithObjectInArray:names atIndex:i+1];
        }];
    }
}

我只是在这里输入了代码,所以一些方法的名称可能会拼写错误。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/17920169

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档