Swift Combine 接收器在第一次错误后停止接收值

Ser*_*nik 5 error-handling swift combine

我将我的项目从 RxSwift 移动到 Combine 我有一个逻辑,我希望发布者每次单击按钮时都发出事件。实际点击按钮执行pushMe.send()

pushMe
            .print("Debug")
            .flatMap { (res) -> AnyPublisher<Bool, Error> in
                return Future<Bool, Error>.init { closure in
                    closure(.failure(Errors.validationFail))
                }.eraseToAnyPublisher()
            }
            .sink(receiveCompletion: { completion in
                print("Completion received")
            }, receiveValue: { value in
                print("Value = \(value)")
            })
            .store(in: &subscriptions)
Run Code Online (Sandbox Code Playgroud)

控制台结果

Debug: receive value: (true)
Completion received
Debug: receive value: (true)
Debug: receive value: (true)
Run Code Online (Sandbox Code Playgroud)

我不明白为什么接收器只在第一个事件中收到错误。其余的点击将被忽略。

Yod*_*ama 8

flatMap 是做什么的 -

  1. 订阅给定的发布者(假设是 XPublisher)。
  2. 将 XPublisher 发出的错误和输出值(未完成事件/完成)发送到下游。

因此,如果您处理 flat Map 内部的错误(这意味着 flatMap 内部的发布者不会发出错误),则 flatMap 永远不会向下游发送错误。

pushMe
    .print("Debug")
    .flatMap { (res) -> AnyPublisher<Bool, Never> in //<= here
        return Future<Bool, Error>.init { closure in
            closure(.failure(Errors.validationFail))
        }
        .replaceError(with: false) //<= here
        .eraseToAnyPublisher()
    }
    .sink(receiveCompletion: { completion in
        print("Completion received")
    }, receiveValue: { value in
        print("Value = \(value)")
    })
    .store(in: &subscriptions)
Run Code Online (Sandbox Code Playgroud)

否则,您可以在 fatMap 之外处理错误。这里的问题是,一旦出现错误,整个订阅/可取消都会被取消。(在下面的示例中,错误已替换为false值)

pushMe
    .print("Debug")
    .flatMap { (res) -> AnyPublisher<Bool, Error> in 
        return Future<Bool, Error>.init { closure in
            closure(.failure(Errors.validationFail))
        }
        .eraseToAnyPublisher()
    }
    .replaceError(with: false) //<= here
    .sink(receiveCompletion: { completion in
        print("Completion received")
    }, receiveValue: { value in
        print("Value = \(value)")
    })
    .store(in: &subscriptions)
Run Code Online (Sandbox Code Playgroud)

上面的代码中发生了什么。

  1. FlatMaperror输出。
  2. 将错误替换为 false(false因此将收到一个值)
  3. 由于流中出现错误,订阅被取消。


Dáv*_*tor 1

这就是Publisher组合中的工作方式。

可以Publisher发出值或发出完成事件 - 一旦发出完成事件,则Publisher完成并且它不能发出任何其他值或另一个完成事件。如果Publisher发出错误,则错误将作为failure完成发出,这意味着一旦发出错误,则Publisher完成并且无法发出任何更多值。

有几个组合运算符设计用于在不完成Publisher. catch例如,查看一下操作员。