For those who are new to Swift and want to get a feel for Combine. Here's a simple code.
The goal is to understand this today! You don't have to know. I will explain later. Those who understand do not have to read it.
import Combine
let a = CurrentValueSubject<Int, Never>(3)
let b = Just(1)
let publisher = b.combineLatest(a).map{b,a in a + b}
publisher.sink{ added in
print(added)
}
a.send(10)
I don't think it really makes sense, but what is likely to be displayed on standard output (print)?
The answer is
4
11
Two lines are displayed.
The first 4
is 3 + 1
The next 11 is 10 + 1
.
Combine import
import Combine
You can do it with. Available on ** iOS 13 ** and above.
You can easily try it on Playground.
Publisher and Subscriber are the terms that should be remembered for the time being in Combine.
name | Japanese reading | what are you doing |
---|---|---|
Publisher | Publisher | Publish data |
Subscriber | Subscriber | Subscribe to data |
You don't have to understand it, so memorize 2 words for the time being! Publisher, Subscriber
Just is (probably) the easiest Publisher.
Let's go see the definition for the time being. (Excerpt)
@available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *)
public struct Just<Output> : Publisher {
// ... (abridgement)
}
For the time being, it is a Publisher that inherits Publisher. It seems to be a fact that it can be used only on iOS 13.0 or higher.
What is written in this Just explanation is
A publisher that emits an output to each subscriber just once, and then finishes.
From this sentence you can see that:
Forcibly remember that it is a publisher that outputs one value.
With the example code
publisher.sink{ added in
print(added)
}
There was.
Looking at the description of this [sink](https://developer.apple.com/documentation/combine/publisher/sink(receivevalue :)),
Attaches a subscriber with closure-based behavior to a publisher that never fails.
The meaning is unknown, but it seems that it will attach a subscriber, so let's use it.
What happens if you call think with Just earlier?
Just(1).sink { r in
print(r)
}
This will display 1
.
Publisher (Just) outputs 1 only once, and it seems that 1
is displayed because it is entered in r by sinking.
Let's also try CurrentValueSubject <Int, Never> (3)
, which we haven't discussed yet.
CurrentValueSubject<Int, Never>(3).sink { r in
print(r)
}
This will output 3
!
What's the difference with Just ...
What is CurrentValueSubject? Let's look at the definition.
@available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *)
final public class CurrentValueSubject<Output, Failure> : Subject
This guy seems to be ** Subject **. It wasn't Publisher!
Also, it is the same as Just
that it can be used only on iOS 13.0 or higher.
A subject that wraps a single value and publishes a new element whenever the value changes.
Isn't it only Publisher that can publish? I will also go to see the definition of Subject.
public protocol Subject : AnyObject, Publisher
Apparently Subject is a ** Publisher type **.
Compared to Just
Just | One outputHowever(just)Output oncePublisher |
CurrentValueSubject | Wrap one value to get a new value when the value changesPublishTo doSubject |
The difference with Just is that when the value changes, it publishes the new value! Let's try it.
import Combine
let a = CurrentValueSubject<Int, Never>(3)
a.sink{ added in
print(added)
}
a.value = 100
a.value = 10000
a.send(9999)
What is likely to be output? The answer is
3
100
10000
9999
It prints every time the a.value changes. It seems that a.send () can also express the change of value.
Most of the first example has been explained.
import Combine
let a = CurrentValueSubject<Int, Never>(3)
let b = Just(1)
let publisher = b.combineLatest(a).map{b,a in a + b}
publisher.sink{ added in
print(added)
}
a.send(10)
After that, if you know let publisher = b.combineLatest (a) .map {b, a in a + b}
, you can understand the meaning of the code.
combineLatest
First, let's pay attention to b.combineLatest (a)
.
What does this mean?
let a = CurrentValueSubject<Int, Never>(3)
let b = Just(1)
So both a and b are Publishers.
Let's take a look at the description of combineLatest.
Subscribes to an additional publisher and publishes a tuple upon receiving output from either publisher.
This guy seems to be both Subscribe and Publish.
Try to move it.
import Combine
let a = CurrentValueSubject<Int, Never>(3)
let b = Just(1)
let publisher = b.combineLatest(a).sink{r in
print(r)
}
What is going to happen with this?
The correct answer is
(1, 3)
Speaking of which, combineLatest said earlier that it would return tuples.
Let's change the value of a. Add 3 lines of code.
import Combine
let a = CurrentValueSubject<Int, Never>(3)
let b = Just(1)
let publisher = b.combineLatest(a).sink{r in
print(r)
}
a.value = 4
a.value = 5
a.send(6)
What's going on?
The correct answer is
(1, 3)
(1, 4)
(1, 5)
(1, 6)
The value of b remains unchanged and is printed by changing the value of a.
Did you see the movement?
Looking at the definition,
public func combineLatest<P>(_ other: P) -> Publishers.CombineLatest<Self, P> where P : Publisher, Self.Failure == P.Failure
It's long and unclear, but it's returning Publishers.CombineLatest <Self, P>
.
Publishers.CombineLatest
public struct CombineLatest<A, B> : Publisher
It's ** Publisher **.
So b.combineLatest (a)
is a function that makes two Publishers one Publisher.
map
map is
Transforms all elements from the upstream publisher with a provided closure.
It seems that everything will be transformed.
Looking at the definition
public func map<T>(_ transform: @escaping (Self.Output) -> T) -> Publishers.Map<Self, T>
After all, this always returns Publisher!
The example given earlier in combineLatest
.
import Combine
let a = CurrentValueSubject<Int, Never>(3)
let b = Just(1)
let publisher = b.combineLatest(a).sink{r in
print(r)
}
a.value = 4
a.value = 5
a.send(6)
Result is,
(1, 3)
(1, 4)
(1, 5)
(1, 6)
It was.
Try adding a map after combineLatest in this code.
import Combine
let a = CurrentValueSubject<Int, Never>(3)
let b = Just(1)
let publisher = b.combineLatest(a)
.map{(b,a) in a+b}
.sink{r in print(r)}
a.value = 4
a.value = 5
a.send(6)
What is likely to return?
The correct answer is
4
5
6
7
this is
(1, 3)
(1, 4)
(1, 5)
(1, 6)
You can see that each of these results adds two values.
I changed .map {(b, a) in a + b}
to .map {(b, a) in a}
.
What will the output be?
import Combine
let a = CurrentValueSubject<Int, Never>(3)
let b = Just(1)
let publisher = b.combineLatest(a)
.map{(b,a) in a}
.sink{r in print(r)}
a.value = 4
a.value = 5
a.send(6)
The correct answer is
3
4
5
6
To use Combine | iOS 13.Above 0import Combine |
What is Just | Output the value only oncePublisher |
What is a sink | Subscribe to the value output by Publisher(Subscribe)Can be processed |
CurrentValueSubject | The value can be changed and the changed value is output.Publisher(Subject) |
How to change the value of CurrentValueSubject? | CurrentValueSubject.Assign to value or CurrentValueSubject.send(value)Enter a value in |
What is combineLatest | Makes two publishers one publisher and returns the value as a tuple. |
What is map | Transform all values from publisher |
Did you understand the behavior of the code below the goal?
import Combine
let a = CurrentValueSubject<Int, Never>(3)
let b = Just(1)
let publisher = b.combineLatest(a).map{b,a in a + b}
publisher.sink{ added in
print(added)
}
a.send(10)