使用 dispatchgroup 在 for 循环中等待任务完成,如果失败则退出循环

问题描述

我试图根据条件退出 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()
  }
}

解决方法

return 从当前作用域返回。

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

您必须重构代码才能实现您想要做的事情。

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

OR(如果此代码异步执行)您必须考虑等待一个任务完成/失败,然后再触发另一个。

更新

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

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)
,
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