【问题标题】:How make Combine's flatMap to complete overall stream?如何让Combine的flatMap完成整体流?
【发布时间】:2021-08-28 08:36:17
【问题描述】:

我有一些这样的代码

func a() -> AnyPublisher<Void, Never> {
    Future<Void, Never> { promise in
        DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
            print(1)
            promise(.success(()))
        }
    }
    .eraseToAnyPublisher()
}

func b() -> AnyPublisher<Void, Never> {
    Future<Void, Never> { promise in
        DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
            print(2)
            promise(.success(()))
        }
    }
    .eraseToAnyPublisher()
}

var tempBag = Set<AnyCancellable>()

let subject = CurrentValueSubject<Int, Never>(1)

subject
    .flatMap({ _ in a() })
    .flatMap({ _ in b() })
    .print()
    .sink(receiveCompletion: { _ in
        tempBag.removeAll()
    }, receiveValue: {  })
    .store(in: &tempBag)

所以,我在流的根目录中有一些无法完成的主题,在 flatMap 运算符中有一些可完成的发布者。我希望在最后一个 flatMap 的发布者完成时完成整个流。所以,我希望控制台看起来像这样:

receive subscription: (FlatMap)
request unlimited
1
2
receive value: (())
receive finished

但实际结果是

receive subscription: (FlatMap)
request unlimited
1
2
receive value: (())

我怎样才能做到这一点?

【问题讨论】:

  • 您知道flatMap 的行为方式吗?您似乎误解了它的工作原理。 flatMap(f) 将其上游发布的 每个 元素 x 替换为发布者 f(x) 发布的所有元素。因此,如果 flatMap 的上游从未完成,则它永远不会完成。如果你只想要 1 个元素,在最后一个 flatMap 之后添加 prefix(1) 怎么样?

标签: ios swift combine


【解决方案1】:

您遇到的问题是您的SubjectCurrentValueSubject)永远不会完成,因此整个链条永远不会完成。您需要的是一个发布者,它发出单个值,然后在序列的顶部完成,以及一个中间体,等待它跟踪的所有发布者完成,然后再自行完成。

您已经有一个发布者,它会做一件事然后完成...它由a() 返回。要等到a()b() 都完成,您可以使用combineLatest,因为它创建的发布者在它组合的所有发布者完成之前不会完成。整个事情看起来像:

a()
.combineLatest(b())
.print()
.sink(receiveCompletion: { _ in
    tempBag.removeAll()
}, receiveValue: { _ in () })
.store(in: &tempBag)

输出

receive subscription: (CombineLatest)
request unlimited
1
2
receive value: (((), ()))
receive finished

【讨论】:

    猜你喜欢
    • 2020-09-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多