首页 > 解决方案 > 订阅返回的发布者后如何触发流程?

问题描述

我有一个返回发布者的函数。该发布者提供后台进程的结果。我只想在订阅发布者时触发后台进程,这样就不会丢失任何结果。后台进程可以多次更新其结果,因此Future不适合使用 with 的变体。

private let passthroughSubject = PassthroughSubject<Data, Error>()

// This function will be used outside.
func fetchResults() -> AnyPublisher<Data, Error> {
     return passthroughSubject
     .eraseToAnyPublisher()
     .somehowTriggerTheBackgroundProcess()
}

extension MyModule: MyDelegate {
     func didUpdateResult(newResult: Data) {
          self.passthroughSubject.send(newResult)
     }
}

我尝试了什么?

未来:

Future<Data, Error> { [weak self] promise in
     self?.passthroughSubject
          .sink(receiveCompletion: { completion in
               // My logic
          }, receiveValue: { value in
               // My logic    
          })
          .store(in: &self.cancellableSet)
      self?.triggerBackgroundProcess()
}.eraseToAnyPublisher()

以我想要的方式工作,但订阅者只被调用一次(逻辑)。

延期:

Deferred<AnyPublisher<Data, Error>>(createPublisher: { [weak self] in
   defer {
      self?.triggerBackgroundProcess()
   }
   return passthroughSubject.eraseToAnyPublisher()
}

调试器显示一切都是正确的:首先是returntrigger但订阅者不是第一次被调用。

receiveSubscription

passthroughSubject
.handleEvents(receiveSubscription: { [weak self] subscription in 
   self?.triggerBackgroundProcess()
})
.eraseToAnyPublisher()

效果与 相同Deffered

我想实现的目标有可能吗?或者,最好创建一个公共发布者订阅它并从后台进程接收结果。并且该fetchResults()函数不返回任何内容?

在此先感谢您的帮助。

标签: swiftcombine

解决方案


在我看来,您的最后一段代码是一个完全可行的解决方案:在检测到订阅之前不要触发后台进程。例子:

let subject = PassthroughSubject<String, Never>()
var storage = Set<AnyCancellable>()
func start() {
    self.subject
        .handleEvents(receiveSubscription: {_ in
            print("subscribed")
            DispatchQueue.main.async {
                self.doSomethingAsynchronous()
            }
        })
        .sink { print("got", $0) }
        .store(in: &storage)
}
func doSomethingAsynchronous() {
    DispatchQueue.global(qos: .userInitiated).async {
        DispatchQueue.main.async {
            self.subject.send("bingo")
        }
    }
}

推荐阅读