使用Combine的last(where:)操作符如何获取发射值?如何获取值4?
Combine中
last(where:)无法获取值的问题及解决方案 问题代码
enum MyError: Error { case test } let subject = PassthroughSubject<Int, MyError>() var subscriptions = Set<AnyCancellable>() subject .eraseToAnyPublisher() .last(where: { $0 % 2 == 0 }) .sink(receiveCompletion: { print("Completed with: ", $0) }, receiveValue: { print($0) }) .store(in: &subscriptions) subject.send(1) subject.send(2) subject.send(4) subject.send(completion: .failure(MyError.test))
当前输出
Completed with: failure(__lldb_expr_1.MyError.test)
问题原因
last(where:)操作符的核心行为是:仅当上游Publisher正常完成(发送.finished事件)时,才会发射符合条件的最后一个值。如果上游以失败终止(发送.failure事件),该操作符会直接传递失败事件,不会触发receiveValue回调,自然无法输出你期望的4。
解决方案
方案1:捕获错误,让Publisher正常完成
通过catch操作符捕获上游错误,转换为正常完成的Publisher,这样last(where:)就能正常发射符合条件的最后值:
enum MyError: Error { case test } let subject = PassthroughSubject<Int, MyError>() var subscriptions = Set<AnyCancellable>() subject .eraseToAnyPublisher() .catch { _ in Empty<Int, Never>() } // 捕获错误后发送空的正常完成事件 .last(where: { $0 % 2 == 0 }) .sink(receiveCompletion: { print("Completed with: ", $0) }, receiveValue: { print($0) }) // 会输出4 .store(in: &subscriptions) subject.send(1) subject.send(2) subject.send(4) subject.send(completion: .failure(MyError.test))
输出结果:
4 Completed with: finished
方案2:手动跟踪最后符合条件的值(保留错误信息)
如果需要保留上游的错误信息,同时获取最后符合条件的值,可以用scan操作符跟踪过程中的有效值:
enum MyError: Error { case test } let subject = PassthroughSubject<Int, MyError>() var subscriptions = Set<AnyCancellable>() var lastValidValue: Int? subject .eraseToAnyPublisher() .scan(nil as Int?) { lastValid, current in current % 2 == 0 ? current : lastValid } .sink(receiveCompletion: { completion in print("Completed with: ", completion) if let value = lastValidValue { print(value) // 输出4 } }, receiveValue: { value in lastValidValue = value }) .store(in: &subscriptions) subject.send(1) subject.send(2) subject.send(4) subject.send(completion: .failure(MyError.test))
输出结果:
Completed with: failure(__lldb_expr_1.MyError.test) 4
总结
要通过last(where:)获取值,必须保证上游Publisher最终是正常完成状态;如果需要保留错误事件,就得手动跟踪符合条件的最后值,再在完成回调中处理。
内容的提问来源于stack exchange,提问作者chlkdst
相关产品推荐
相关产品推荐

