简体   繁体   English

结合将发布者分配给 PassthroughSubject

[英]Combine assign publisher to PassthroughSubject

I have following RxSwift view model code:我有以下 RxSwift 视图模型代码:

private(set) var num = BehaviorRelay<Int>(value: 1)
private let indexTrigger = PublishRelay<Int>()
private let disposeBag = DisposeBag()

private func setupBindings() {
   //...
   self.num.distinctUntilChanged().bind(to: self.indexTrigger).disposed(by: self.disposeBag)
}

func numSelected(num: Int) {
   self.num.accept(num)
}

This code is working fine and does what I want.这段代码工作正常,可以做我想要的。 I'm trying to do same, but with swift Combine framework with following code:我正在尝试做同样的事情,但是使用带有以下代码的 swift Combine 框架:

@Published private(set) var num: Int = 1
private let indexTrigger = PassthroughSubject<Int, Never>()
private var subscriptions = Set<AnyCancellable>()

private func setupBindings() {
   //...
   self.$num.removeDuplicates().sink(receiveValue: { [weak self] num in
      self.indexTrigger.send(num)
   }).store(in: &self.subscriptions)
}

func numSelected(num: Int) {
   self.num = num
}

So RxSwift binding looks much clean and simple and without need of weak.所以 RxSwift 绑定看起来非常干净和简单,不需要弱。 I tried to check assign(on:) method in combine, but seems it is not the one.我试图在 combine 中检查assign(on:)方法,但似乎不是那个。 Is there way to do same thing?有没有办法做同样的事情?

It looks like you're trying to "chain" publishers.看起来您正试图“链接”出版商。 The way to chain publishers is not to have two separate publishers with the second one poked by a .sink and a .send ;链接发布者的方法不是让两个独立的发布者通过.sink.send戳第二个; it is to use .flatMap in the pipeline.它是在管道中使用.flatMap

In your comment, you said that what you really want to do in the second publisher is "trigger request".在您的评论中,您说您在第二个发布者中真正想做的是“触发请求”。 That sounds like networking.这听起来像网络。 So in your .flatMap you would provide a publisher that does the networking.因此,在您的.flatMap您将提供一个负责网络连接的发布者。

Here is a toy example, just to show you the form:这是一个玩具示例,只是为了向您展示表单:

import UIKit
import Combine

func delay(_ delay:Double, closure:@escaping ()->()) {
    let when = DispatchTime.now() + delay
    DispatchQueue.main.asyncAfter(deadline: when, execute: closure)
}

class ViewController: UIViewController {

    @Published var num: Int = 1
    var storage = Set<AnyCancellable>()
    
    func setupPipeline() {
        $num.removeDuplicates()
            .flatMap { self.makeNetworkingFuture($0) }
            .sink { print($0) }
            .store(in: &self.storage)
    }
    
    func makeNetworkingFuture(_ i: Int) -> AnyPublisher<Int,Never> {
        URLSession.shared.dataTaskPublisher(for: URL(string:"https://www.example.com")!)
            .map{_ in i}
            .replaceError(with: -1000)
            .eraseToAnyPublisher()
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        self.setupPipeline()
        delay(1) { self.num = 1 }
        delay(2) { self.num = 1 }
        delay(3) { self.num = 2 }
        delay(4) { self.num = 2 }
        delay(5) { self.num = 3 }
    }
}

That's a very silly example, in the sense that although we do some networking, we don't show the result of that networking.这是一个非常愚蠢的例子,从某种意义上说,虽然我们进行了一些联网,但我们并没有显示该联网的结果 I'm just outputting an Int (the same Int that came down the pipeline from num ).我只是输出一个 Int (从num进入管道的同一个 Int )。 But when you run the example, what you will see in the output is 1 , then 2 , then 3 , proving that we are removing duplicates, and networking is actually taking place on each of those occasions, as you can demonstrate to yourself in other ways.但是,当你运行的例子,你会在输出中看到的是1 ,然后2 ,然后3 ,证明我们正在删除重复和网络实际发生在每这些场合中,你可以在其他证明自己方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM