Adding condition based on previous result on DispatchQueue

时间:2017-11-13 06:36:48

标签: ios swift grand-central-dispatch

Is it possible to set a condition on the next queue of DispatchQueue? Supposed there are 2 API calls that should be executed synchronously, callAPI1 -> callAPI2. But, callAPI2 should be only executed if callAPI1 returning true. Please check code below for more clear situation:

    let dispatchQueue: DispatchQueue = DispatchQueue(label: "queue")
    let dispatchGroup = DispatchGroup()

    var isSuccess: Bool = false


    dispatchGroup.enter()
    dispatchQueue.sync {
        self.callAPI1(completion: { (result) in
            isSuccess = result
            dispatchGroup.leave()
        }
    }

    dispatchGroup.enter()
    dispatchQueue.sync {
        if isSuccess { //--> This one always get false
            self.callAPI2(completion: { (result) in
                isSuccess = result
                dispatchGroup.leave()
            })
        } else {
            dispatchGroup.leave()
        }
    }

    dispatchGroup.notify(queue: DispatchQueue.main, execute: {
        completion(isSuccess) //--> This one always get false
    })

Currently above code always returning isSuccess as false despite on callAPI1's call returning true, which cause only callAPI1's is called.

1 个答案:

答案 0 :(得分:1)

所有非游乐场代码直接输入答案,预计会出现少量错误。

您似乎正在尝试将异步调用转换为同步调用,而您尝试此操作的方式根本不起作用。假设callAPI1是异步的,则在:

之后
self.callAPI1(completion: { (result) in
   isSuccess = result
}

完成块(很可能)尚未运行,您无法立即测试isSuccess,如:

self.callAPI1(completion: { (result) in
   isSuccess = result
}
if isSuccess
{
   // in all probability this will never be reached
}

将代码包装到同步块中无效

dispatchQueue.sync
{
   self.callAPI1(completion: { (result) in
      isSuccess = result
   }
   // at this point, in all probability, the completion block
   // has not yet run, therefore...
}
// at this point it has also not run

同步调度只是在不同的队列上运行其块,等待以完成它;如果该块包含异步代码,就像你的那样,它就不会神奇地同步 - 它正常异步执行,同步调度的块终止,同步调度返回,你的代码继续。同步调度没有实际效果(除了在阻止当前队列的同时在不同队列上运行块)。

如果您需要对多个异步调用进行排序,您可以通过多种方式执行此操作。一种方法是简单地通过完成块链接调用。使用这种方法,您的代码变为:

self.callAPI1(completion: { (result) in
   if !result { completion(false) }
   else
   {
      self.callAPI2(completion: { (result) in
         completion(result)
      }
   }
}

使用信号量

如果使用上述模式进行了很长时间的此类调用,则代码可以变得非常嵌套,在这种情况下,您可以使用信号量对调用进行排序,而不是嵌套。使用wait(),可以使用简单的信号量来阻止(线程)执行,直到使用{{1}向(通过未阻塞的线程)发出信号 }。

注意这里强调阻止,一旦你引入了阻止执行的能力,就必须考虑各种问题:其中包括UI响应 - 阻止UI线程不好;死锁 - 例如,如果发出信号量等待和信号操作的代码在同一个线程上执行,那么在等待之后将没有信号......

这是一个示例Swift Playground脚本,用于演示使用信号量。该模式遵循原始代码,但除了布尔值外还使用信号量。

signal()

或...

避免嵌套的另一种方法是设计函数(或运算符),它们采用两种异步方法并通过实现嵌套模式生成单个方法。然后可以将长嵌套序列简化为更线性的序列。这种方法留作练习。

HTH