当两个其他的完成块被调用时,调用完成块。

3

我有一个函数doEverything,它带有一个完成块。它调用另外两个函数doAlphadoBeta,这两个函数都有完成块。这两个函数应该异步运行。在这两个函数都调用其完成块后,我想调用doEverything的完成块。

目前,代码看起来像这样:

func doEverything(completion: @escaping (success) -> ())) {
    var alphaSuccess = false
    var betaSuccess = false

    doAlpha { success in
        alphaSuccess = success
    }

    doBeta { success in
        betaSuccess = success
    }

    // We need to wait here
    completion(alphaSuccess && betaSuccess)
}

doAlphadoBeta 应该同时运行,并且一旦它们都完成,就应该使用 alpha 和 beta 的结果调用完成块。

我已经了解了调度组和障碍的概念,但我不确定哪个是最合适的,它们如何引入新的作用域(涉及我正在使用的两个变量),以及我应该如何实现。

非常感谢。


1
您可以使用 dispatch_group_t: https://dev59.com/0mct5IYBdhLWcg3wqfP9 - Larme
我担心完成块会在doAlpha和doBeta的完成块被调用之前被调用,但我可以看到那个线程上的第二个答案,使用dispatch_group_enter(group)和dispatch_group_leave(group),正是我想要的。谢谢。 - Josh Paradroid
2个回答

7

Grand Central Dispatch (GCD) 是一个非常好的选择,如果你想要在编程中实现某些功能,你可以使用 DispatchQueueDispatchGroup,具体实现如下:

Swift 3:

func doEverything(completion: @escaping () -> ()) {
    let queue = DispatchQueue(label: "reverseDomain", attributes: .concurrent, target: .main)
    let group = DispatchGroup()

    group.enter()
    queue.async (group: group) {
        print("do alpha")

        group.leave()
    }

    group.enter()
    queue.async (group: group) {
            print("do beta")

        group.leave()
    }

    group.notify(queue: DispatchQueue.main) {
        completion()
    }
}

或者,您可以按照以下方式实现(我认为这种方式更易读):
func doEverything(completion: @escaping () -> ()) {
    let queue = DispatchQueue(label: "reverseDomain", attributes: .concurrent, target: .main)
    let group = DispatchGroup()

    queue.async (group: group) {
        print("do alpha")
    }

    queue.async (group: group) {
        print("do beta")
    }

    group.notify(queue: DispatchQueue.main) {
        completion()
    }
}

请注意,我从completion闭包中删除了success标志。

在这种情况下,“do beta”(第二个queue.async的执行)直到“do alpha”(第一个queue.async的执行)完成后才会执行,这是因为queue目标是.main。如果您想让两个queue.async并行工作,则无需创建额外的队列,同一个队列应该可以完成工作,方法是用以下代码替换:

let queue = DispatchQueue(label: "reverseDomain", attributes: .concurrent, target: .main)

使用:

let queue = DispatchQueue(label: "reverseDomain", attributes: .concurrent)

现在,系统将控制queue.async任务同时运行的方式(显然,在这两个任务完成后,group.notify将被执行)。
希望这有所帮助。

我认为这就是我在寻找的!我只是想知道是否需要创建一个队列,因为我的doAlpha和doBeta调用已经是异步的。非常感谢。 - Josh Paradroid
@JoshParadroid请检查答案的更新,我提到了你想要实现的解决方案。 - Ahmad F

0
Ahmad F的答案是正确的,但是由于我的带回调函数的函数会立即返回(像大多数函数一样),而回调函数稍后执行,所以我不需要创建一个新队列。这是原始代码,经过更改使其正常工作。
func doEverything(completion: @escaping (success) -> ())) {
    var alphaSuccess = false
    var betaSuccess = false

    let group = DispatchGroup()

    group.enter()
    doAlpha { success in
        alphaSuccess = success
        group.leave()
    }

    group.enter()
    doBeta { success in
        betaSuccess = success
        group.leave()
    }

    group.notify(queue: DispatchQueue.main) {
        completion(alphaSuccess && betaSuccess)
    }
}

我其实并不想把完成的调用强制放在主线程上,但是¯\_(ツ)_/¯


我本可以使用group.wait()而不是group.notify(...),从而不在主线程上分派。 - Josh Paradroid

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接