如何在 Combine 中使用另一个发布者重新发布 PassthroughSubject

How to re-publish a PassthroughSubject using another publisher in Combine

当前(工作)情况:

在我们的应用程序中,我们有多个 PassthroughSubject<Void, Never> 类型的发布者。 此发布者的订阅者在 .sink() 闭包内发送相同类型的发布者。在一个简单的操场上,它看起来像这样:

//: A UIKit based Playground for presenting user interface

import UIKit
import PlaygroundSupport
import Combine

class MyViewController : UIViewController {

    // MARK: - Observables
    let initialPublisher: PassthroughSubject = PassthroughSubject<Void, Never>()
    let rePublisher = PassthroughSubject<Void, Never>()

    // MARK: - Observer
    private var cancellableSubscriber = Set<AnyCancellable>()

    override func loadView() {
        // MARK: - View Setup
        let view = UIView()
        let button = UIButton(type: .system)
        button.frame = CGRect(x: 100, y: 100, width: 200, height: 20)
        button.setTitle("Button", for: .normal)
        button.addTarget(self, action: #selector(buttonAction), for: .touchUpInside)
        view.addSubview(button)
        self.view = view

        // MARK: - Subscriptions

        // Event of initial publisher is received and re-published using another subject.
        initialPublisher
            .sink { [weak self] in
                self?.rePublisher.send()
            }
            .store(in: &cancellableSubscriber)

        // The re-published event is received.
        rePublisher
            .sink {
                print("Received!")
            }
            .store(in: &cancellableSubscriber)
    }

    @objc private func buttonAction() {
        self.initialPublisher.send()
    }
}
// Present the view controller in the Live View window
PlaygroundPage.current.liveView = MyViewController()

首选(无效)解决方案:

我没有使用 .sink() 闭包和另一个 PassthroughSubject 订阅和重新发布,而是想使用 .receive(subscriber: AnySubscriber) 重新发布初始发布者但是不知何故它似乎不起作用或者我理解错了 .receive 方法。我尝试了以下但没有运气。

问题:

我怎样才能使下面的代码工作,或者它是否是正确的方法?如果没有,是否有比我们上面的代码更优雅的重新发布方式?

澄清:

如果有什么不清楚或者您需要更多示例,请在下面发表评论,我会尝试更新我的问题。

class MyViewController : UIViewController {

    // MARK: - Observables
    let initialPublisher: PassthroughSubject = PassthroughSubject<Void, Never>()
    let rePublisher = PassthroughSubject<Void, Never>()
    var subscriber = AnySubscriber<Void, Never>()

    // MARK: - Observer
    private var cancellableSubscriber = Set<AnyCancellable>()

    override func loadView() {
        // MARK: - View Setup
        let view = UIView()
        let button = UIButton(type: .system)
        button.frame = CGRect(x: 100, y: 100, width: 200, height: 20)
        button.setTitle("Button", for: .normal)
        button.addTarget(self, action: #selector(buttonAction), for: .touchUpInside)
        view.addSubview(button)
        self.view = view

        // MARK: - Subscriptions

        //Republishing
        subscriber = AnySubscriber(initialPublisher)

        // Event of initial publisher is received and re-published.
        rePublisher.receive(subscriber: subscriber)

        // // The re-published event is received.
        rePublisher
            .sink {
                print("Received!") // <-- does not work!
            }
            .store(in: &cancellableSubscriber)
    }

    @objc private func buttonAction() {
        self.initialPublisher.send()
    }
}

我觉得你太辛苦了。只需传递 AnyPublisher 而不是试图将两个主题联系在一起。尝试将它们捆绑在一起甚至没有意义,因为任何人都可以在其中任何一个上调用发送。

class MyViewController : UIViewController {
    let initialPublisher: PassthroughSubject = PassthroughSubject<Void, Never>()
    var rePublisher: AnyPublisher<Void, Never> {
        initialPublisher.eraseToAnyPublisher()
    }
    private var cancellableSubscriber = Set<AnyCancellable>()

    override func loadView() {
        super.loadView()
        let button: UIButton = {
            let result = UIButton(type: .system)
            result.frame = CGRect(x: 100, y: 100, width: 200, height: 20)
            result.setTitle("Button", for: .normal)
            result.addTarget(self, action: #selector(buttonAction), for: .touchUpInside)
            return result
        }()
        view.backgroundColor = .white
        view.addSubview(button)
        
        rePublisher
            .sink {
                print("Received!") // works!
            }
            .store(in: &cancellableSubscriber)
    }

    @objc private func buttonAction() {
        initialPublisher.send()
    }
}