简体   繁体   中英

using dispatchgroup wait for task completion in for loop and exit from loop if failure

I am trying to exit from for loop according to condition but I ran into the issue as it does not exit even from the loop. Here is a loop of my code.

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()
  }
}

The return returns from current scope.

In this case it's returning from the failureBlock: {} and NOT from the for loop scope.

You have to refactor the code to achieve what you are trying to do.

EITHER (in case this code is executing synchronously) you can return a success value true | false from the function by making function 's return type Bool and removing the failureBlock argument.

OR (in case this code is executing asynchronously) you have to think of waiting on one task to complete/fail before triggering the other.

UPDATE

I think following might be a simplified version of this code -

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM