当 flatMapped 时,Combine 的未来永远不会完成

JAH*_*lia 2 ios combine

我有以下简单的Future

class ViewModel {
    var cancellables = Set<AnyCancellable>()
    func test() {
        let trigger = PassthroughSubject<Void, Error>()

       let future =  Future<String, Error> { promise in
                       promise(.success("Future Succeded"))
                   }

        trigger
        .flatMap { future }
        .sink(receiveCompletion: { completion in
            print("completion received \(completion)")
        }, receiveValue: { val in
            print("value received \(val)")
        })
        .store(in: &cancellables)

        trigger.send(())
    }
}
Run Code Online (Sandbox Code Playgroud)

我不知道为什么在与另一个发布者(在本例中为 a PassthroughSubject)平面映射时它永远不会完成,它只产生值。

当它不是平面映射时,它会产生值并正常完成。

don*_*als 5

这种行为可能看起来很奇怪,但很有意义。完成Future不完成PassthroughSubject。因此,您可以继续通过 发送值,PassthroughSubject这将导致Future创建和触发新实例。通常,aPublisher只能完成或出错一次。因此,如果完成 theFuture将触发sink完成闭包,则意味着 thePassthroughSubject不能再产生新值,这是不可取的,因为 aPassthroughSubject通常永远不会完成(除非您直接告诉它)。

与您的示例类似,此代码也仅触发一次完成:

var cancellables = Set<AnyCancellable>()

(0..<2).publisher
  .flatMap { _ in return (0..<5).publisher }
  .sink(receiveCompletion: { completion in
    print("completion received \(completion)")
  }, receiveValue: { val in
    print("value received \(val)")
  })
  .store(in: &cancellables)
Run Code Online (Sandbox Code Playgroud)

原因是创建的发布者是一个会发布两个值的发布者,然后它就完成了。如果flatMap发布者会导致sink调用(0..<2)完成,则意味着发布者完成了,除非它仍有要发送的值,因此尚未完成。

长话短说,开始的发布者决定流何时完成;不是平面映射的发布者。