问题
From the documentation of reactive swift I could understand about Flattening
. Examples of which can be found here. In the section Flattening event streams
everything has been discussed perfectly.
I'm confused about flatmap
. According to the docs, it Maps each event from self to a new producer, then flattens the resulting producers according to strategy - concat/merge/latest
. So, it should be similar to flattening
I guess.
But, I could not generate a similar behavior. For example consider the following code segment. If I change the flattening strategy like concat/merge/latest
, the output does not change.
let (numbersSignal, numbersObserver) = Signal<String, NoError>.pipe()
numbersSignal.producer.flatMap(.concat) { value -> SignalProducer<String, NoError> in
print("Outer Signal Producer \(value)")
return SignalProducer<String, NoError> {
observer, lifetime in
print("Inner Signal Producer \(value)")
observer.send(value: "Inner")
observer.sendCompleted()
}
}.observe(on: UIScheduler()).startWithValues { result in
print("Observer \(result)")
}
numbersObserver.send(value: "A")
numbersObserver.send(value: "B")
numbersObserver.send(value: "C")
numbersObserver.sendCompleted()
Output:
Outer Signal Producer A
Inner Signal Producer A
Observer Inner
Outer Signal Producer B
Inner Signal Producer B
Observer Inner
Outer Signal Producer C
Inner Signal Producer C
Observer Inner
Can anyone clear this up?
Moreover, can any examples be provided about flatmap
differentiating the effect of merge, concat, latest
?
回答1:
What's happening here is that the producers you're creating in the flatMap
complete synchronously; you're calling sendCompleted
within the start closure itself. So within flatMap
, it's calling start
on the producer and the producer is finishing before that call to start
even returns. This means there's no opportunity for flatMap
to apply different strategies; each producer finishes immediately after it is started.
We can see how the different strategies behave by creating an asynchronous producer within flatMap
(note I'm using the most recent versions of Swift and ReactiveSwift, so I'm using Never
instead of NoError
):
let (numbersSignal, numbersObserver) = Signal<TimeInterval, Never>.pipe()
numbersSignal.producer
.flatMap(.concat) { value -> SignalProducer<TimeInterval, Never> in
print("Outer Signal Producer \(value)")
return SignalProducer(value: value).delay(value, on: QueueScheduler())
}
.startWithValues { result in
print("Observer \(result)")
}
numbersObserver.send(value: 5)
numbersObserver.send(value: 2)
numbersObserver.send(value: 1)
In this example we're sending TimeInterval
values, and each created producer sends the given value with a delay equal to that value.
concat: Each subsequent producer waits for the previous one to complete before starting, so the values are printed in the exact order we send them.
Outer Signal Producer 5.0
Outer Signal Producer 2.0
Outer Signal Producer 1.0
Observer 5.0
Observer 2.0
Observer 1.0
merge: All producers are started immediately once we send values, so they all run concurrently. Therefore, the values are printed smallest to largest i.e. the producers with the shortest delays complete first.
Outer Signal Producer 5.0
Outer Signal Producer 2.0
Outer Signal Producer 1.0
Observer 1.0
Observer 2.0
Observer 5.0
latest: Only the last value is printed because each producer is cancelled as a new value comes in; only the last value is allowed to run to completion.
Outer Signal Producer 5.0
Outer Signal Producer 2.0
Outer Signal Producer 1.0
Observer 1.0
Note that in all three cases, the "Outer Signal Producer" message was printed first for all values. This is because the closure we give to flatMap
is always run immediately when a new value comes in. But the resulting producers are started and cancelled in accordance with the flatten strategy.
来源:https://stackoverflow.com/questions/58607151/differences-among-flatmap-strategies-in-reactiveswift