繁体   English   中英

DispatchGroup 逻辑工作流

[英]DispatchGroup logical workflow

我正在尝试按如下方式实现DispatchGroup ,但是如果第一个调用返回true ,那么第二个调用返回false ,那么整体结果将返回false

但是,如果第一个调用返回false ,那么第二个调用返回true ,那么总体结果将返回false ,这不是我所期望的。

如果任何调用返回false ,我想返回false 我怎么能处理这个问题?

 func storeInformation(id: String?, _ completion: @escaping (Bool) -> ()) {
    guard
      let id =  id
    else {
      completion(false)
      return
    }
    let dispatchGroup = DispatchGroup()
    var groupResult: Bool = false
    dispatchGroup.enter()
    storeFeatures { success in
      if success {
        groupResult = true
      } else {
        groupResult = false
      }
      dispatchGroup.leave()
    }
    
    dispatchGroup.enter()
    storeClasses { success in
      if success {
        groupResult = true
      } else {
        groupResult = false
      }
      dispatchGroup.leave()
    }
    dispatchGroup.notify(queue: .main) {
      completion(groupResult)
    }
  }

  private func storeClasses(_ completion: @escaping(Bool) -> Void) {
    postClasses { (error) in
      if let _ = error {
        completion(false)
      } else {
        completion(true)
      }
    }
  }

  private func storeFeatures(_ completion: @escaping(Bool) -> Void) {
    postFeatures { (error) in
      if let _ = error {
        completion(false)
      } else {
        completion(true)
      }
    }
  }

如果我们查看您的storeClassesstoreFeatures ,我们会发现它们并不是真正返回 Bool 的操作; 它们本质上是试图发布可能失败的东西。 因此,您真正想知道的不是某事返回true还是false ,而是它是否失败 这就是你真正的意思——在编程中,说出你的意思总是更好。

使用 Combine 框架,我们可以用难以置信的简洁性来表达这种行为。 当我们有多个异步操作要同时执行时,这就是 Merge。 如果其中一个失败,则整个 Merge 失败 换句话说,你想做的事情实际上是自动的!

例如,想象一下,我们通过将您的发布操作包装在<Void,Error>类型的延迟期货中来表达它们。 假设我们有方法storeClassesFuturestoreFeaturesFuture可以生成这些 Future。 那么你只需要说:

Publishers.Merge(storeClassesFuture(), storeFeaturesFuture())

这就是它的全部内容! 如果您使用sink订阅该 Merge ,则它会收到finished的完成或failure的完成。 你猜怎么着? 当且仅当一个或两个发布操作失败时,它才会收到failure完成! 只有当它们都成功时,它才会收到finished的完成,这正是您想知道的。

作为测试平台,这是您的storeInformation的示例实现(出于示例的目的,我忽略了字符串):

var storage = Set<AnyCancellable>()
enum Oops : Error { case darn }
func storeInformation() {
    Publishers.Merge(storeClassesFuture(), storeFeaturesFuture())
        .receive(on: DispatchQueue.main)
        .sink { (completion) in
            switch completion {
            case .failure: print("at least one of them failed")
            case .finished: print("they both succeeded")
            }
            print("---")
        } receiveValue: { _ in }
        .store(in: &storage)
}

只是作为一个随机测试,这里有两个可以随机成功或失败的期货:

func storeClassesFuture() -> AnyPublisher<Void,Error> {
    Deferred {
        Future<Void,Error> { promise in
            if Bool.random() {
                print("storeClassesFuture succeeded")
                promise(.success(()))
            } else {
                print("storeClassesFuture failed")
                promise(.failure(Oops.darn))
            }
        }
    }.eraseToAnyPublisher()
}
func storeFeaturesFuture() -> AnyPublisher<Void,Error> {
    Deferred {
        Future<Void,Error> { promise in
            if Bool.random() {
                print("storeFeaturesFuture succeeded")
                promise(.success(()))
            } else {
                print("storeFeaturesFuture failed")
                promise(.failure(Oops.darn))
            }
        }
    }.eraseToAnyPublisher()
}

这是来自重复调用storeInformation的一些示例 output:

storeClassesFuture succeeded
storeFeaturesFuture succeeded
they both succeeded
---
storeClassesFuture failed
storeFeaturesFuture failed
at least one of them failed
---
storeClassesFuture failed
storeFeaturesFuture succeeded
at least one of them failed
---
storeClassesFuture failed
storeFeaturesFuture failed
at least one of them failed
---
storeClassesFuture failed
storeFeaturesFuture succeeded
at least one of them failed
---
storeClassesFuture succeeded
storeFeaturesFuture succeeded
they both succeeded
---
storeClassesFuture succeeded
storeFeaturesFuture succeeded
they both succeeded
---
storeClassesFuture failed
storeFeaturesFuture succeeded
at least one of them failed
---
storeClassesFuture failed
storeFeaturesFuture succeeded
at least one of them failed
---
storeClassesFuture succeeded
storeFeaturesFuture succeeded
they both succeeded
---

如您所见,您所追求的逻辑完美地通过两个可失败 Future 的合并来表达。

(这种事情是采用 Combine 框架而不是使用 DispatchGroup 的一个很好的理由。我发现我以前用 DispatchGroup 做的所有事情都可以用 Combine 做得更好。这恰好是一个特别清晰的例子。)

你在这里有一个“AND”语义,所以你应该在你的代码中写下它:

let dispatchGroup = DispatchGroup()
var groupResult: Bool = true // identity for AND
dispatchGroup.enter()
storeFeatures { success in
  groupResult = groupResult && success // here!
  dispatchGroup.leave()
}

dispatchGroup.enter()
storeClasses { success in
  groupResult = groupResult && success // and here
  dispatchGroup.leave()
}
dispatchGroup.notify(queue: .main) {
  completion(groupResult)
}

当每项任务完成时,你想表达的想法是

如果前一组结果为真且成功为真,则组结果应为真

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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