ios - 使用 `.receive(on: DispatchQueue.main)` 时未接收到输入

标签 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()

最佳答案

AnyCancellablesubscribe<S>(_ subject: S) -> AnyCancellable 返回会调用cancel()当它被取消初始化时。因此,如果您不保存它,它将在调用 block 超出范围时被取消初始化。

在我从 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 s)将在包含类被取消初始化时被取消初始化。

过时:

如果你想要所有的解决方案Cancellable可以以更流畅的方式使用,您可以扩展 Cancellable因此:

extension Cancellable {

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

}

关于ios - 使用 `.receive(on: DispatchQueue.main)` 时未接收到输入,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56677669/

相关文章:

ios - swift:如何请求 HealtKit 许可?

ios - 快速组合 : `first(_ n: Int)` equivalent to RxSwift `take(_ n: Int)` ?

快速字典 : map within a map

ios - Spritekit 中的新场景没有显示任何内容?

swift - 用于获取 PassthroughSubject 发布者值的单元测试

swift - 使用 Combine 时处理 Swift 5 独占性执行

ios - 如何在 iOS 上编辑 NativeScript-Angular RadDataForm UIStepper?

iphone - 在包含错误的 UITextfield 周围制作一个红色边框

ios - 在 Share Extension iOS 上显示网络事件指示器

ios - 文本字段/发送按钮在 JSQMessagesViewController 上的键盘弹出时消失