Current (working) situation:
In our app we have several publishers of type PassthroughSubject<Void, Never>
.
The subscriber of this publisher send out the same type of publisher within the .sink()
closure. In a simple playground it would look like that:
//: 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()
Prefered (non-working) solution:
Instead of subscribing and re publishing using the .sink()
closure and another PassthroughSubject
I wanted to re-publish the initial publisher using .receive(subscriber: AnySubscriber)
However somehow it doesn't seem to work or maybe I'm understanding the .receive
method wrong. I tried the following without luck.
Question:
How can I make the below code work, or is it even the correct way? If not, are there more elegant ways to re-publish than in our code above?
Clarification:
If something is unclear or of you need further examples please leave a comment below and I will try to update my question.
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()
}
}
CodePudding user response:
I think you are working too hard. Just pass the AnyPublisher around instead of trying to tie two Subjects together. It doesn't even make sense to try to tie them together because anybody can call send on either of them.
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()
}
}