【问题标题】:using dispatchgroup wait for task completion in for loop and exit from loop if failure使用 dispatchgroup 在 for 循环中等待任务完成,如果失败则退出循环
【发布时间】:2021-06-02 04:39:10
【问题描述】:

我试图根据条件退出 for 循环,但我遇到了这个问题,因为它甚至没有退出循环。 这是我的代码循环。

var isFailure = true
let dispatchGroup = DispatchGroup()
var myFailureTask: Int?
for item in 1...5 {
  dispatchGroup.enter()
  test(item: item, completion: {
    print("Success\(item)")
    dispatchGroup.leave()
  }, failureBlock: {
    print("Failure\(item)")
    myFailureTask = item
    dispatchGroup.leave()
    return
  })
  dispatchGroup.wait()
}
dispatchGroup.notify(queue: .main) {
  if let myFailure = myFailureTask {
    print("task failure \(myFailure)")
  } else {
    print("all task done")
  }
}
func test(item: Int,completion: @escaping(() -> ()), failureBlock: @escaping(() -> ())) {
    Thread.sleep(forTimeInterval: TimeInterval(item))
  isFailure = !isFailure
  if isFailure {
    failureBlock()
  } else {
    completion()
  }
}

【问题讨论】:

  • 您需要在循环中的某处有一个break 才能退出它,但是break 需要放在循环的同步部分。顺便说一句,你为什么需要打破循环,你要解决什么问题?
  • 当循环中的一项失败时,我需要退出循环,因为 API 调用取决于循环中前一项的成功。
  • 那么这个 - stackoverflow.com/questions/51004245/… - 应该可以帮助你。
  • 我只是做了一些改变,工作起来很有魅力。谢谢@Cristik

标签: ios swift for-loop dispatchgroup


【解决方案1】:

return 从当前作用域返回。

在这种情况下,它从 failureBlock: {} 返回,而不是从 for 循环范围返回。

你必须重构代码来实现你想要做的事情。

(如果此代码同步执行)您可以返回一个successtrue |通过使function 的返回类型为Bool 并删除failureBlock 参数,从函数中删除false

或者(如果此代码异步执行)您必须考虑在触发另一个任务之前等待一个任务完成/失败。

更新

我认为以下可能是此代码的简化版本-

var isFailure: Bool = false

func callTest(for item: Int) {
    print("task initiated \(item)")
    test(item: item, completion: {
        print("task succeeded \(item)")
        if item < 5 {
            callTest(for: item+1)
        } else {
            print("all tasks done")
        }
    }, failureBlock: {
        print("task failed \(item)")
    })
}

func test(item: Int, completion: @escaping (() -> Void), failureBlock: @escaping (() -> Void)) {
    Thread.sleep(forTimeInterval: TimeInterval(item))
    isFailure.toggle()
    if isFailure {
        failureBlock()
    } else {
        completion()
    }
}

callTest(for: 1)

【讨论】:

  • 谢谢。在我的测试函数中,会有一个异步任务,即API调用,第二个任务依赖于前一个任务。有没有办法从循环中返回?
【解决方案2】:
var isFailure = false
let dispatchGroup = DispatchGroup()
var myFailureTask: Int?
for item in 1...5 {
  dispatchGroup.enter()
  test(item: item, completion: {
    print("Success\(item)")
    dispatchGroup.leave()
  }, failureBlock: {
    print("Failure\(item)")
    myFailureTask = item
    dispatchGroup.leave()
  })
  if isFailure == true {
    break
  }
  dispatchGroup.wait()
}
dispatchGroup.notify(queue: .main) {
  if let myFailure = myFailureTask {
    print("task failure \(myFailure)")
  } else {
    print("all task done")
  }
}
func test(item: Int,completion: @escaping(() -> ()), failureBlock: @escaping(() -> ())) {
    Thread.sleep(forTimeInterval: TimeInterval(item))
  isFailure = !isFailure
  if isFailure {
    failureBlock()
  } else {
    completion()
  }
}```
Made few changes work like a charm.
Any one has better idea please comment

【讨论】:

  • 我认为这可以简化 - 请参阅我的答案的 UPDATE
猜你喜欢
  • 2014-07-19
  • 1970-01-01
  • 2012-12-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-04
相关资源
最近更新 更多