Search code examples
iosswiftrx-swift

What difference does it make to subscribe to a normal type and a observable type in here?


  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)


Solution

  • 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 :)