使用`.receive(on:DispatchQueue.main)`时不接收输入

时间:2019-06-20 00:56:43

标签: ios swift combine

我正在尝试使用.receive(on: DispatchQueue.main)切换到下游的主线程,但是使用.subscribe(:).sink(receiveValue:)时却没有收到输入。如果我不更改线程,则会收到正确的输入。

发布者

extension URLSessionWebSocketTask {
  struct ReceivePublisher: Publisher {
    typealias Output = Message
    typealias Failure = Error

    let task: URLSessionWebSocketTask

    func receive<S>(subscriber: S) where S: Subscriber, Output == S.Input, Failure == S.Failure {
      task.receive { result in
        switch result {
        case .success(let message): _ = subscriber.receive(message)
        case .failure(let error): subscriber.receive(completion: .failure(error))
        }
      }
    }
  }
}

extension URLSessionWebSocketTask {
  func receivePublisher() -> ReceivePublisher {
    ReceivePublisher(task: self)
  }
}

订户

extension ViewModel: Subscriber {
  typealias Input = URLSessionWebSocketTask.Message
  typealias Failure = Error

  func receive(subscription: Subscription) {}

  func receive(_ input: URLSessionWebSocketTask.Message) -> Subscribers.Demand {
    // Handle input here.
    // When using `.receive(on:)` this method is not called when should be.
    return .unlimited
  }

  func receive(completion: Subscribers.Completion<Error>) {}
}

订阅

socketTask.receivePublisher()
      .receive(on: DispatchQueue.main)
      .subscribe(viewModel)
socketTask.resume()

1 个答案:

答案 0 :(得分:1)

AnyCancellable返回的subscribe<S>(_ subject: S) -> AnyCancellable在取消初始化后将调用cancel()。因此,如果不保存它,则在调用块超出范围时将被取消初始化。

在我从WWDC看过的视频和教程中,从未讨论过如何使用它。我所看到的是,人们正在向RxSwift的DisposeBag解决方案过渡。

更新Beta 4: 现在,Combine在AnyCancellable上提供了一个名为store(in:)的方法,该方法几乎可以完成我以前的解决方案。您可以将AnyCancellable存储在一组AnyCancellable中:

var cancellables = Set<AnyCancellable>()
...
override func viewDidLoad() {
    super.viewDidLoad()
    ...
    socketTask.receivePublisher()
        .receive(on: DispatchQueue.main)
        .subscribe(viewModel)
        .store(in: &cancellables)
}

这样,当包含类被取消初始化时,数组(和所有AnyCancellable)将被取消初始化。

已过时:

如果您希望所有Cancellable都可以以更好的方式使用的解决方案,则可以这样扩展Cancellable

extension Cancellable {

    func cancel(with cancellables: inout [AnyCancellable]) {
        if let cancellable = self as? AnyCancellable {
            cancellables.append(cancellable)
        } else {
            cancellables.append(AnyCancellable(self))
        }
    }

}