Swift等待异步任务

时间:2017-03-03 00:40:46

标签: ios swift asynchronous

在后台主题中我们有:

defer {
    cleanup()
}

loadData()

if error {
    return
}

processData()

DispatchQueue.main.asyncAfter(deadline: delay) {  //Delay = now + 0-2 seconds
     updateUI()
}

问题是我们希望确保延迟cleanUp()代码在updateUI()之后运行。而且,由于updateUI()运行异步。

,因此不会发生这种情况

我的想法是睡眠/阻塞延迟时间而不是异步运行。这将在cleanUp()完成后延迟updateUI()运行。

你怎么能这样做?或者有更好的方法吗?

3 个答案:

答案 0 :(得分:4)

您可以使用信号量告诉清理任务等待updateUI完成:

let semaphore = DispatchSemaphore(value: 1)
defer {
    semaphore.wait()
    cleanup()
}

loadData()

if error {
    // If we exit here, the semaphore would have never been used
    // and cleanup will run immediately
    return
}

processData()
semaphore.wait() // here, we claim the semaphore, making cleanup
                 // wait until updateUI is done
DispatchQueue.main.asyncAfter(deadline: delay) {
     updateUI()
     semaphore.signal()
}

答案 1 :(得分:0)

意识到我可以改变代码的结构:

loadData()

if error {
    log.error("Error")
} else {
   processData()
}

DispatchQueue.main.asyncAfter(deadline: delay) {  //Delay = now + 0-2 seconds
  updateUI()
  cleanup()
}

答案 2 :(得分:0)

另一种替代方法是使用DispatchGroup()

func doWork() {

   let group = DispatchGroup()

   group.enter() //Enter #1
   loadData { result in

      switch (result) {
      case .success(_):
           group.enter()//Enter #2
           processData { group.leave()//Leave #2 }
      case .failure(let error):
           //Do something nice with the error
           print(error)
      }

      group.leave()//Leave #1
    }

    //All the code inside this block will be executed on the mainThread when all tasks will be finished.
     group.notify(queue: .main) { [weak self] in

         guard let strongSelf = self else { return }

         strongSelf.updateUI()
         strongSelf.cleanup()
     }
}

private func updateUI() {
    //All your stuff
}

private func cleanup() {
    //All your stuff
}

private func loadData(completion: (Result<(), Error>) -> ()) {
    //All your stuff
    if error {
       completion(.failure(error))
    }
    else {
       completion(.success(()))
    }
}

private func processData(completion: () -> ()) {
    //All your stuff
    completion()
}