let s = "Hello World"
let string = BehaviorSubject(value: s)
//Example 1
string
.map { _ in "hhh" }
.subscribe(onNext: { element in
print(element)
}, onCompleted: {
print("completed")
}
)
//Example 2
string
.flatMap { s -> Observable<String> in
Observable.just("lll")
}
.subscribe(onNext: { element in
print(element)
}, onCompleted: {
print("completed")
}
)
//Example 3
let aaa = string
.map { _ in "hhh" }
//Example 4
let bbb = string
.flatMap { s -> Observable<String> in
Observable.just("lll")
}
I'm pretty new to RX world, in example 1 & 2, I use map
and flatMap
to test to test out this behaviour. one of the major difference between them is map
return normal value type whereas the flatMap
returns Observable type.
In example 3 & 4, it shows that the type of both aaa
and bbb
are Observable<String>
..
Now, since at the end they become the same thing, why do you even need flatMap
to return a specific Observable
type? or why do you need map
to return a normal value
type?
(I know that flatMap
can do other things, it's not part of this confusion)
map
operator is used to transform the value and pass the transformed value to next operator where as flatmap
flattens the hierarchy of observables and exposes it as single operator
Use case for map
and flatmap
In general you use map
if you wanna transform the value you have received in your current operator and pass it on to next operator usually synchronously. Example in your case no matter what value is assigned to BehaviorRelay
String
you wanna return "hhh" which is straight forward synchronous value transformation so map
makes sense
string
.map { _ in "hhh" }
.subscribe(onNext: { element in
print(element)
}, onCompleted: {
print("completed")
}
)
flatmap
is used to flatten the hierarchy of observables and expose it to next operator simply as a single observable. Example assume you are implementing search, once the value is triggered, you wanna make API call and pass the response to next operator. Now making API call is a asynchronous operation and you know that simple map
will not cut through then you might use flatmap
let string = BehaviorRelay<String>(value: "abcd")
string
.flatMap { s -> Observable<Response> in
return Observable<Response>.create({ (observer) -> Disposable in
//make api call here
//pass data / error using observer.onNext or observer.onError()
return Disposables.create()
})
}
.subscribe(onNext: { element in
print(element)
}, onCompleted: {
print("completed")
}
)
So here actual API call is made by observable inside the flatMap
operator but for outer world it looks like BehaviorRelay itself transformed the value of type string to Response.
Which is perfect because one need not know the nitty-gritty involved in making API call :)
But to be really honest, if you are really implementing search you would rather choose flatMapLatest
rather than flatmap
. Read more on flatMap
and flatMapLatest
for better understanding :)