调度组未阻止来自 运行 的代码

Dispatch Group not blocking code from running

我希望调度组中的代码在任何其他事情发生之前完成执行,实质上是阻止应用程序执行任何操作,直到此代码完成。但是,我无法让调度组阻止来自 运行 的附加代码。我已经尝试了这里关于堆栈的几乎所有建议,但我不知道我在做什么。

我的函数:

- (void)myFunction {

    NSString *myString = @"Hello world";

    dispatch_group_t group = dispatch_group_create();

    NSLog(@"1 entering the dispatch group");

    dispatch_group_enter(group);
    [self doSomething:myString completion:^{
        dispatch_group_leave(group);
        NSLog(@"2 we have left the dispatch group");
    }];
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        NSLog(@"3 notifying that the dispatch group is finished");
    }];
    NSLog(@"4 all process are complete, we are done");
}

我想要通过日志语句输出 = 1,2,3,4

我通过日志语句得到的输出 = 1,4,2,3

为什么我的代码跳过调度组并在 2 和 3 之前打印 4?对我做错了什么的任何建议表示赞赏。谢谢!

更新:

这是我的 doSomething 方法。我的代码一直挂在 dismiss 调用上。

doSomething() {

    viewController.dismiss(animated: false completion: { [weak self] in 
        doMoreCode()
    })
}

这里没有任何东西真正阻止。 dispatch_group_notify 只是说 "when the group finishes, run this." 您打算使用的工具是 dispatch_group_wait。如果你想要 1,2,3,4,那么你的意思是:

- (void)myFunction {

    NSString *myString = @"Hello world";

    dispatch_group_t group = dispatch_group_create();

    NSLog(@"1 entering the dispatch group");

    dispatch_group_enter(group);
    [self doSomething:myString completion:^{
        NSLog(@"2 we have left the dispatch group");
        dispatch_group_leave(group);
    }];

    dispatch_group_wait(group, DISPATCH_TIME_FOREVER);

    NSLog(@"3 notifying that the dispatch group is finished");

    NSLog(@"4 all process are complete, we are done");
}

myFunction 当然不能在 iOS 中的主队列上调用(因为它会阻塞并且您绝不能阻塞主队列)。而且它也不能在 doSomething:completion: 用于其完成处理程序的同一队列上调用(因为该队列将在 dispatch_group_wait 处被阻塞)。

请记住,dispatch_queue_notify 只是将一个块添加到队列中,以便在将来的某个时间成为 运行。所以有点不清楚你期望 3 和 4 是如何工作的(在我的例子中我只是折叠它们,但也许你正在寻找其他东西)。

另一种方法是 阻止应用程序,只在应该的时候将内容安排到 运行。在这种情况下,您可以使用主队列。它看起来像这样:

- (void)myFunction {

    NSString *myString = @"Hello world";

    dispatch_group_t group = dispatch_group_create();

    NSLog(@"1 entering the dispatch group");

    dispatch_group_enter(group);
    [self doSomething:myString completion:^{
        NSLog(@"2 we have left the dispatch group");
        dispatch_group_leave(group);
    }];
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        NSLog(@"3 notifying that the dispatch group is finished");
    });
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        NSLog(@"4 all process are complete, we are done");
    });
}

请注意,在这两个示例中,我在调用 dispatch_group_leave 之前记录了 2。在此示例中,我还在组完成后(按顺序)在主队列上注册了两个要 运行 的东西。在这种情况下,myFunction 将立即 return(因此它可以在主队列上 运行),但所有内容都应按顺序打印出来。

假设 doSomething 异步运行,您可以等待该组,但通常最好采用异步模式,例如允许 myFunction 立即到 return,但要为该方法提供您自己的完成处理程序:

- (void)myFunctionWithCompletion:(void (^)())completion {
    NSString *myString = @"Hello world";

    dispatch_group_t group = dispatch_group_create();

    NSLog(@"1 entering the dispatch group");

    dispatch_group_enter(group);
    [self doSomething:myString completion:^{
        dispatch_group_leave(group);
        NSLog(@"2 we have left the dispatch group");
    }];
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        NSLog(@"3 notifying that the dispatch group is finished");
    });
}

并像这样使用它:

[self myFunctionWithCompletion:^{
    NSLog(@"4 all process are complete, we are done");
}];

// note, it's not done when it gets here, though, because it's asynchronous

显然,在上面的例子中,调度组完全是多余的,但我假设你在做多个异步任务,这就是你引入调度组的原因。如果它真的只是一个异步任务,你就可以这样做:

- (void)myFunctionWithCompletion:(void (^)())completion {
    NSString *myString = @"Hello world";

    [self doSomething:myString completion:^{
        NSLog(@"The asynchronous doSomething is done");
        completion();
    }];
}