What is the difference between PublishSubject and PublishRelay in RxSwift? - reactive-programming

I am new to RxSwift programming.
I am confused between the two while coding. Which one should be used to store datasource of table and how to decide that ?

A PublishSubject can emit an error or completed event while a PublishRelay cannot.
A PublishSubject conforms to the ObserverType protocol while the PublishRelay does not.
Another important point that was alluded to by #RobMayoff in his comment. Neither a PublishSubject nor a PublishRelay stores state, so neither of them are a good idea to "store datasource of table".
Fortunately, you don't need to store the state yourself because the DataSource object that the items operator creates internally stores it.
In other words, you don't need to use a Subject or Relay (of any sort) to feed a table view. Just use an Observable.

If you look at the interface to PublishRelay you can see that it wraps a PublishSubject but it hides this from its interface. So you can only send it accept(_ event: Element) which means you cannot send it error or completed Events only next elements.
public final class PublishRelay<Element>: ObservableType {
private let subject: PublishSubject<Element>
// Accepts `event` and emits it to subscribers
public func accept(_ event: Element) {
self.subject.onNext(event)
}
/// Initializes with internal empty subject.
public init() {
self.subject = PublishSubject()
}
//...
}
Anyhow, if you look at examples of tableview using RxCocoa they just wrap an array as an Observable usually using Just or create that you then pass to the tableview using RxCocoa's interface. You don't really want a Subject just a plain observable.

Related

How to make a Publisher that sends multiple values in Combine

Could you help me with a Combine issue?
I'd like to make a Publisher which sends multiple values during its lifetime. In more detail, I want to wrap a method with a completion handler into a Publisher, and the completion handler is supposed to be called multiple times. For example, it's a method used for receiving messages via WebSocket like this:
webSocketClient.receiveMessage { message, error in
// this closure is called multiple times, everytime a message comes
...
}
How can I wrap this into a Publisher? I want something like AnyPublisher<String, Error> in the end.
Wrapping these is super easy when I use other FRP libraries. For example, in ReactiveSwift, it can be achieved by using SignalProducer.init(_ startHandler:). In RxSwift, it's Observable.create method.
In Combine, I found Future can be used when there's only one value to emit, but it doesn't suit my current case. I couldn't find any initializer for Publisher for this use case.
Also, I found Effect.run in TCA (The Composable Architecture) which can be used for this case. It seems custom publishers are used in its implementation, which seems a bit complicated for simple usage, but is this the only way? Are there any other easy ways to achieve the similar behavior?
I feel this is a quite common scenario, so I'd like to know how Combine users are handling this case in practice.
Thank you in advance!
Basically there are two options.
In a SwiftUI environment make the class which contains the code conform to ObservableObject and add a #Published property
class ViewModel : ObservableObject {
#Published var message = ""
func loadData() {
webSocketClient.receiveMessage { message, error in
self.message = message
...
}
}
}
In the view create a #StateObject of the view model to be notified about new messages.
Or declare a subject to send values
class ViewModel {
let subject = PassthroughSubject<String,Never>()
func loadData() {
webSocketClient.receiveMessage { message, error in
self.subject.send(message)
...
}
}
}
To receive the notifications get an instance of the class, call sink on the subject and store the result into a strong reference.

PassthroughSubject with no initial value

I want to create a Swift Combine publisher that transmits a value and always gives the latest value when someone subscribes to it. However I want to only transmit a value once I have one - from an asynchronous call that’s triggered by the first subscriber. Pass through subject doesn’t work for that need, is there any good way to accomplish this?
You can use CurrentValueSubject for this:
let subject = CurrentValueSubject<T, E>(someValue)
func whatever() -> AnyPublisher<T, E> {
return subject.dropFirst().eraseToAnyPublisher()
}

In Swift Combine, is the "root" object always a Subject?

In Apple's WWDC videos on Swift Combine, they always use NSNotificationCenter as the publisher of messages. However, a Publisher does not appear to have any ability to actually send a message on demand. That functionality appears to be in Subject.
Am I correct in assuming that a Subject must therefor be the root object of any chain of Publishers? Apple provides two built-in subjects called: CurrentValueSubject and PassthroughSubject.
But I assume I can write my own Subject using the appropriate protocols?
In Swift Combine, Publishers are a protocol describing an object which can transmit values over time.
A Subject is an extended publisher which knows how to send imperatively.
Neither Publisher nor Subject are concrete classes with implementation; they are both protocols.
Take a look at the Publisher protocol (and remember that a Subject is an extended Publisher):
public protocol Publisher {
associatedtype Output
associatedtype Failure : Error
func receive<S>(subscriber: S) where S : Subscriber, Self.Failure == S.Failure, Self.Output == S.Input
}
To build a custom publisher you need only implement the receive function (and provide type information), in which you are given access to a subscriber. How would you send data to that subscriber from WITHIN the publisher?
For this we look at the Subscriber protocol to see what's available:
public protocol Subscriber : CustomCombineIdentifierConvertible {
...
/// Tells the subscriber that the publisher has produced an element.
///
/// - Parameter input: The published element.
/// - Returns: A `Demand` instance indicating how many more elements the subcriber expects to receive.
func receive(_ input: Self.Input) -> Subscribers.Demand
}
As long as you've saved a reference to any/all subscribers which have connected, your publisher can easily send changes into the pipeline by calling receive on the subscriber. However, you'll have to manage subscribers and diff changes on your own.
A Subject behaves the same but instead of streaming changes into the pipeline, it simply provides a send function for someone else to call. The two concrete Subjects that Swift provides have additional features like storage.
TL;DR changes aren't sent to publishers they're sent to subscribers. Subjects are publishers that can accept some input.

What design pattern do I need for a single object which can receive data from different sources?

I'm trying to create some code in Swift that will enable the following functionality. There is a single class (call it the Datastore) that is the main interface into the code - this is what most users of the API will deal with most of the time.
This Datastore class is flexible. You could use it with data from a text file, or from Bluetooth data, or from data coming in over WiFi, etc. I call these providers of data. So, for example, you could have a BTProvider class which will take bluetooth data and send it to the Datastore when it arrives. One Datastore will never need to get data from multiple providers of data.
What design patterns or language tools help me to achieve this?
I thought about using protocols, but it feels backwards - a protocol defines which methods an object can respond to - but in this case, that will be the Datastore object - of which there is only one. In my head I feel like I want a reverse-protocol - something where I can guarantee "this object /calls/ these methods on another object". Then all the providers could implement this, and the Datastore could have a method "setProvider: ProviderOfData" where provider of data is the name of the reverse-protocol.
This would be a lot easier if I could poll the providers from the Datastore (then they could implement a protocol that defines methods like 'getMostRecentData', but due to the nature of it (asynchronous data receiving from WiFi, Bluetooth, etc.) this isn't possible and doesn't feel elegant - though if you have ideas I'm open to them!
This doesn't seem like this is the first time this would've been done, so I'm interested in how it's commonly done so I don't have to reinvent the wheel.
something where I can guarantee "this object /calls/ these methods on another object".
Seems like what you need is the Delegate-Pattern
You can have a DataStore (Swift is camel case) and this class can implement several delegate protocols. Example:
class DataStore {
// logic of the DataStore
}
You said that your app is mostly one class (the DataStore), so I am guessing you someone initialise your providers from it. I would suggest:
// Provider Factory
extension DataStore {
func makeBluetoothProvider() {
let btProvider = BTProvider()
btProvider.delegate = self
}
// creation of other providers, or you can create them all at once.
}
Not the important part, the DataStore is the delegate of your providers, that way, when they retrieve data, they can call the DataStore. I would have a protocol like this:
protocol ProviderDelegate: class {
func provider(_ provider: Provider, didFinishReceiving data: Data)
}
extension DataStore: ProviderDelegate {
func provider(_ provider: Provider, didFinishReceiving data: Data) {
// read data and do something with it...display it, save it, etc.
}
}
Provider would be a general class for all the providers, probably with network requests or similar basic data. One example would be:
class Provider {
var delegate: ProviderDelegate
var data: Data
}
class BTProvider: Provider {
// logic only for bluetooth provider
}
Depending on how differently your providers behave, you can have a delegate protocol for each and an extension of DataStore implementing each of this protocols. That only if the behaviours are too different from each other, which I don't think.
UPDATE ADDRESSING COMMENT: Protocol can provide code
A protocol can provide code, let me show you an example:
protocol Provider {
weak var delegate: ProviderDelegate { get set }
func fetchData(with url: URL)
func processData(data: Data)
}
extension Provider {
func processData(data: Data) {
// do some processing that all providers have to do equally
// probably also call delegate to tell DataStore it is ready
}
}
Your provider class would implement the method and can choose to implement a new processData or just use the default one. If it implements it, there is no need to call for override, you would just no longer have access to the protocol method. You provider can look like this:
class BTProvider: Provider {
weak var delegate: Provider?
func fetchData(with url: URL) {
// do some logic to fetch data for this provider
processData(data: whateverWasFetched)
}
}

Does a read only BehaviorSubject interface exist in RX and if not, is it a bad idea to make one?

Implementations of rx provide BehaviorSubject<T> and Variable<T> as mechanisms for modeling properties that change over time (a useful replacement for C# INotifyPropertyChanged).
Generally these are exposed as Observable<T> but it would be more useful to expose properties as something like:
class ObservableValue<T> : Observable<T>{
var currentValue:T { get }
}
This can be created along these lines in swift:
class ObservableValue<Element> : ObservableType {
typealias E = Element
private let subject:BehaviorSubject<E>
var currentValue:E {
get {
return try! subject.value()
}
}
init(subject:BehaviorSubject<E>) {
self.subject = subject
}
func subscribe<O: ObserverType where O.E == E>(observer: O) -> Disposable {
return self.subject.subscribe(observer)
}
}
Does this already exist? and if not is it because it's against the aims of Rx?
The only way around it is to expose a separate currentValue or write consumers that assume the concrete implementation behind the exposed Observable is a BehaviourSubject or somewhere in the chain a replay() has occured e.g. the following snippet doesn't make it explicit that as soon as I subscribe I will get a value:
class MyViewModel {
// 'I will notify you of changes perhaps including my current value'
myProperty:Observable<String>
}
so code has to be written as if its 'asynchronous' with an underlying assumption it will act in an almost synchronous manner rather than:
class MyViewModel {
// 'I have a current value and will notify you of changes going forward'
myProperty:ObservableValue<String>
}
Having thought it over and discussed it a bit more presumably the reason it doesn't (and perhaps shouldn't exist) is that it's an introduction of imperatively accessed state.
Other mechanisms of maintaining state (such as scan) do so within the confines of chained observables rather than as 'dead-end' direct calls such as 'give me the value right now'.
Perhaps it would have it's place in a hybrid reactive/imperative approach but it may just hinder full embracement of the reactive style.
It's analogous to using promises or tasks in half of the code then reverting to synchronous blocking code in other parts.
In most cases what people do is create a standard view model that exposes properties via INotifyPropertyChanged. This allows UI elements to bind to them and receive property change events and keep the UI in sync.
Then if you want an IObservable for said property you take advantage of standard Rx operators that turn events into IObservable. You can google this to find lots of different implementations. You would generally create and consume these observables from something that is observing the view model rather than expose them on the view model directly.