swift 中的两个处理异步调用中的错误如何组合?

How two handle errors in async calls in swift combine?

我有两个异步调用来从服务器获取数据,但我希望它们将它们作为单个响应来处理,还希望为每个响应处理错误。

例如,这里我有两个方法m1()m2()每个方法都可以抛出不同类型的错误。

我们应该等待得到两者的响应 并根据其错误类型显示错误消息。如果没有错误,继续流程。 我们必须使用哪个运算符?我尝试使用 Publishers.Zip & Publishers.Map 无法处理错误。


enum Error1: Error {
    case e1
}

enum Error2: Error {
    case e2
}

func m1() -> Future<Bool, Error1> {
    return Future { promise in
        DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
            promise(.failure(.e1))
        }
    }
}

func m2() -> Future<String, Error2> {
    return Future { promise in
        DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
            promise(.success("1"))
        }
    }
}

不胜感激。!!谢谢。

我认为您 运行 遇到的问题与 Publisher 只能发出一种错误类型这一事实有关。因此,任何时候您尝试组合 m1m2,每个都有不同的错误类型,那么您 运行 就会陷入类型冲突问题。

您可以选择多种方法来解决此问题。我要推荐一个。在我的解决方案中,您的每个请求(您的 Futures)都将使用 Never 的错误类型,但单个请求的成功或失败将在 Result 中进行。这是 Playground 中的代码:

import Foundation
import Combine


enum Error1: Error {
    case e1
}

enum Error2: Error {
    case e2
}

func m1(shouldFail: Bool) -> Future<Result<Bool, Error1>, Never> {
    return Future { promise in
        DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
            if(shouldFail) {
                promise(.success(.failure(.e1)))
            } else {
                promise(.success(.success(true)))
            }
        }
    }
}

func m2(shouldFail: Bool) -> Future<Result<String, Error2>, Never> {
    return Future { promise in
        DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
            if(shouldFail) {
                promise(.success(.failure(.e2)))
            } else {
                promise(.success(.success("1")))
            }
        }
    }
}

let subscribe = m1(shouldFail: false)
    .zip(m2(shouldFail: true))
    .sink {
        (m1:Result<Bool, Error1>, m2:Result<String, Error2>) in

        switch m1 {
            case .success(let boolResult) :
                print("M1 succeeded with result \(boolResult)")
            case .failure(_) :
                print("M1 failed")
        }


        switch m2 {
            case .success(let stringResult) :
                print("M2 succeeded with result \(stringResult)")
            case .failure(_) :
                print("M2 failed")
        }
    }

(请注意,我向您的 m1 和 m2 请求添加了一个 shouldFail 参数,以便您可以在一个或另一个请求失败时处理不同的情况)。

请注意,每个 Futures return 都是 Future<SomeKindOfResult, Never> 的一种。这意味着进入组合管道的期货具有相同的错误类型(恰好是 Never)。这导致看起来非常奇怪的结构:

promise(.success(.failure(.e1)))

这有点奇怪,但它说 Future 同意请求完成,并且 Result 包含该请求的成功或失败。

管道使用 zip 等待两个请求完成。来自 zip 的值是一个元组 (Result<Bool, Error1>, Result<String, Error2>。此元组准确地表示每个请求的成功或失败,并在每种情况下携带适当的值。