I happen to look into Apple's new Combine framework, where I see two things
PassthroughSubject<String, Failure>
CurrentValueSubject<String, Failure>
Can someone explain to me what is meaning & use of them?
I happen to look into Apple's new Combine framework, where I see two things
PassthroughSubject<String, Failure>
CurrentValueSubject<String, Failure>
Can someone explain to me what is meaning & use of them?
I think we can make analogies with real world cases.
PassthroughSubject = A doorbell push button
When someone rings the door, you are notified only if you are at home (you are the subscriber)
PassthroughSubject doesn't have a state, it emits whatever it receives to its subscribers.
CurrentValueSubject = A light switch Someone turns on the lights in your home when you are outside. You get back home and you know someone has turned them on.
CurrentValueSubject has an initial state, it retains the data you put in as its state.
Both PassthroughSubject
and CurrentValueSubject
are publishers that conform to the Subject
protocol which means you can call send
on them to push new values downstream at will.
The main difference is that CurrentValueSubject
has a sense of state (current value) and PassthroughSubject
simply relays values directly to its subscribers without remembering the "current" value:
var current = CurrentValueSubject<Int, Never>(10)
var passthrough = PassthroughSubject<Int, Never>()
current.send(1)
passthrough.send(1)
current.sink(receiveValue: { print($0) })
passthrough.sink(receiveValue: { print($0) })
You'd see that the current.sink
is called immediately with 1
. The passthrough.sink
is not called because it has no current value. The sink will only be called for values that are emitted after you subscribe.
Note that you can also get and set the current value of a CurrentValueSubject
using its value
property:
current.value // 1
current.value = 5 // equivalent to current.send(5)
This isn't possible for a passthrough subject.
PassthroughSubject
. You are ignoring the cancellable return on passthrough.sink(receiveValue: { print($0) })
, so it will never print anything, even if you send some value afterward. You should save the return to a variable. –
Carthusian CurrentValueSubject
. If you add the code passthrough.send(90)
on the last line, you will never get 90 printed. That's my point. –
Carthusian PassthroughSubject
is used for representing events. Use it for events like button tap.
CurrentValueSubject
is used representing state. Use it for storing any value, say state of switch as off and on.
Note: @Published
is kind of CurrentValueSubject
.
PassthroughSubject
and CurrentValueSubject
are both Publisher
s — a type introduced by Combine — that you can subscribe to (performing operations on values when values are available).
They both are designed to make it easy to transfer to using the Combine paradigm. They both have a value and an error type, and you can "send" values to them (making the values available to all subscribers)
The main difference between the two that I've seen is that CurrentValueSubject
starts with a value, while PassthroughSubject
does not. PassthroughSubject
seems easier to grasp conceptually, at least for me.
PassthroughSubject
can easily be used in place of a delegate pattern, or to convert an existing delegate pattern to Combine.
//Replacing the delegate pattern
class MyType {
let publisher: PassthroughSubject<String, Never> = PassthroughSubject()
func doSomething() {
//do whatever this class does
//instead of this:
//self.delegate?.handleValue(value)
//do this:
publisher.send(value)
}
}
//Converting delegate pattern to Combine
class MyDel: SomeTypeDelegate {
let publisher: PassthroughSubject<String, Never> = PassthroughSubject()
func handle(_ value: String) {
publisher.send(value)
}
}
Both of these examples use String
as the type of the value, while it could be anything.
Hope this helps!
PassthroughSubject
is suitable for event like tap action
CurrentValueSubject
is suitable for state
Already a lot of good answers posted in this thread, just thought of adding this answer for someone who is coming from using RxSwift.
PassThroughSubject
is like PublishSubject
where it broadcasts an event to its subscribers, probably with some value passed along.
CurrentValueSubject
is similar to BehaviorRelay
where a single value is persisted with the subject instance and passed along during the event broadcast.
CurrentValueSubject and PassthroughSubject are two subjects in combine and both are publishers which means subscriber can subscribe these publishers and can listen for emitted events.
Both are different in terms of how they behave with their subscribers which are listening to them. Let's discuss both individually
CurrentValueSubject says please give me some initial value on subject creation. Like as below code
var disposeBag = [AnyCancellable]()
var subject : CurrentValueSubject<String, Never> = CurrentValueSubject("Mashhood")
While subscribing to subject
subject.subscribe(on: DispatchQueue.global(qos: .background))
.sink { value in
print(value)
}
.store(in: &disposeBag)
As subscriber subscribe that subject it will immediately receive current value that is
OUTPUT
Mashhood
And as we send another value like as
subject.send("Qadeer")
then output looks like as
OUTPUT
Mashhood
Qadeer
Conclusion Subscriber subscribing have following points
It will always get a value on subscription it can be value given in subject creation in case if no value sent to subject but if something sent to subject before subscribing then it will be received on subscription as most recent value.
It will get most recent value on subscription as discussed in first point and each value submitted after subject subscription.
Now Let's discuss the PassthroughSubject the PassthroughSubject subject does not have initial value on subject creation like as
var passThroughSubject: PassthroughSubject<String, Never> = PassthroughSubject<String, Never>()
Code for sending value and subscription
passThroughSubject.send("Mashhood")
passThroughSubject.subscribe(on: DispatchQueue.global(qos: .background))
.sink { value in
dump(value)
}
.store(in: &disposeBag)
passThroughSubject.send("Qadeer")
OUTPUT
Qadeer
As you can see it will print only event value that happened after it's subscription. And it does not know about the previous event values.
Conclusion Subscriber subscribing have following points
© 2022 - 2024 — McMap. All rights reserved.