Rx 中的绑定分为两个角色, 即 Producer 和 Receiver. 但如果想要进行双向绑定的话, 则需要使用两个 Producer 或者是两个 Receiver.
绑定的最基本的方法是使用 bindTo
, 它的作用是将一个 Observable(生产者) 绑定到另外一个实体(接收者), 接收者需要实现 ObserverType 协议.
总地来说, bindTo 就是通用版的 subscribe 方法, 在使用时, bindTo 没有副作用, 也没有特殊注意事项.
下面将数据的 observable 和 UI 进行绑定.
先将之前代码的 observable 存放到一个变量中, 并取消掉观察者:
let search = searchCityName.rx.text
.filter { ($0 ?? "").characters.count > 0 } // 这里的 text 是 optional 类型的
.flatMap { text in
return ApiController.shared.currentWeather(city: text ?? "Error")
.catchErrorJustReturn(ApiController.Weather.empty)
}
.observeOn(MainScheduler.instance) // 通过这个操作符将之后的操作调度到主线程执行.
下面就分别来对 search 再进行加工生成不同的 observable 并绑定到不同的 UI 上:
search.map { "\($0.temperature) ℃" }
.bind(to: tempLabel.rx.text)
.addDisposableTo(bag)
search.map { $0.icon }
.bind(to: iconLabel.rx.text)
.addDisposableTo(bag)
search.map { $0.cityName }
.bind(to: cityNameLabel.rx.text)
.addDisposableTo(bag)
search.map { "\($0.humidity) %" }
.bind(to: humidityLabel.rx.text)
.addDisposableTo(bag)
通过上述方式, 就把之前的一个 Observable 分别分离出里面的各种子数据, 然后将这些数据和观察者绑定, 且绑定是单向的, 即将数据源绑定到观察者上面. 这样的写法是清晰, 且类型安全.
这里 RxCocoa 还会帮助我们保证所有的 UI 操作都会在主线程上执行, 因为不在主线程执行的话, 它会出现 fatalError...