在这里订阅普通类型和可观察类型有什么区别?

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")
  }

我是 RX 世界的新手,在示例 1 和 2 中,我使用 mapflatMap 来测试以测试这种行为。它们之间的主要区别之一是 map return 普通值类型,而 flatMap returns Observable 类型。

例3&例4显示aaabbb的类型都是Observable<String>..

现在,既然最后它们变成了同一件事,为什么还需要 flatMap 到 return 特定的 Observable 类型?或者为什么你需要 map 到 return 一个 normal value 类型?

(我知道flatMap可以做其他事情,不属于本次混淆)

map 运算符用于转换值并将转换后的值传递给下一个运算符,其中 flatmap 展平 observables 的层次结构并将其公开为单个运算符

mapflatmap

的用例

一般情况下,如果您想转换在当前运算符中收到的值并将其通常同步传递给下一个运算符,则使用 map。在您的例子中,无论分配给 BehaviorRelay String 什么值,您都想要 return "hhh" 这是直接的同步值转换,因此 map 有意义

string
    .map { _ in "hhh" }
    .subscribe(onNext: { element in
      print(element)
    }, onCompleted: {
      print("completed")
    }
  )

flatmap 用于展平 observable 的层次结构,并将其作为单个 observable 简单地暴露给下一个运算符。示例假设您正在实施搜索,一旦值被触发,您想要进行 API 调用并将响应传递给下一个运算符。现在进行 API 调用是一个异步操作,您知道简单的 map 不会中断,那么您可以使用 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")
        }
    )

所以这里实际的 API 调用是由 flatMap 运算符内部的 observable 发出的,但对于外部世界,它看起来像 BehaviorRelay 本身将字符串类型的值转换为 Response。

这是完美的,因为不需要知道进行 API 调用所涉及的细节 :)

但说实话,如果你真的要实现搜索,你宁愿选择 flatMapLatest 而不是 flatmap。阅读有关 flatMapflatMapLatest 的更多信息,以便更好地理解 :)

它们在几个方面有所不同。

  • map 只为进入其中的每个值发出一个值。而 flatMap 可以为进入其中的每个值发出一个 或更多 个值。

  • 传递给 map 的闭包需要 "pure"(没有副作用)而传递给 flatMap 的闭包可能有副作用(例如磁盘访问,UI 访问和网络访问。)是的,因为 Swift 是一种不纯的语言,您 可以 将副作用放入 map 但这样做会破坏契约。

Sandeep 的回答给出了第二点的例子,下面是第一点的例子:

let string = Observable.of("a", "b", "c")

//Example 1
string
    .map { "\([=10=])-x" }
    .subscribe(onNext: { element in
        print(element) // only prints three values
    }, onCompleted: {
        print("completed")
    }
)

//Example 2
string
    .flatMap { Observable.of("\([=10=])-x", "\([=10=])-y", "\([=10=])-z") }
    .subscribe(onNext: { element in
        print(element) // this prints 9 values.
    }, onCompleted: {
        print("completed")
    }
)