前言
从今天起,我把自己学习RxSwift的官方Example时的感想写下来,或许对有疑惑的人有帮助吧。传送门
加法篇
功能说明
在这三个文本框任意输入数字后,将计算累加后的结果
代码解释
可以说,这个Demo是整个官方Example中最简单的。只需要对三个TextField的rx.text进行监听即可。
源码如下:
@IBOutlet weak var resultLabel: UILabel!
@IBOutlet weak var textField3: UITextField!
@IBOutlet weak var textField2: UITextField!
@IBOutlet weak var textField1: UITextField!
let disposeBag = DisposeBag()
override func viewDidLoad() {
super.viewDidLoad()
self.title = "加法"
// 监听三个textField的text变化,然后进行累+
Observable.combineLatest(textField1.rx.text.orEmpty, textField2.rx.text.orEmpty, textField3.rx.text.orEmpty) { (value1, value2, value3) -> Int in
return (Int(value1) ?? 0) + (Int(value2) ?? 0) + (Int(value3) ?? 0)
}.map({$0.description}) // 将Int -> String
.bind(to: resultLabel.rx.text) // 绑定结果
.disposed(by: disposeBag)
}
这里解释几点:
- textField1.rx.text.orEmpty
看下官方注释:
/// Transforms control property of type `String?` into control property of type `String`.
public var orEmpty: RxCocoa.ControlProperty<String> { get }
其实就是将String?转为String处理,这样我们就不需要考虑String?的情况,也就不需要考虑String为nil的情况。在Rxswift中,对于所有字符串的监听都是转为orEmpty处理的
- combineLatest
其实将可观察序列中,将最新的序列组合起来处理。如下图所示:
再结合代码看,该函数的功能,就一目了然了。
Observable.combineLatest(textField1.rx.text.orEmpty, textField2.rx.text.orEmpty, textField3.rx.text.orEmpty) { (value1, value2, value3) -> Int in
return (Int(value1) ?? 0) + (Int(value2) ?? 0) + (Int(value3) ?? 0)
}.map({$0.description}) // 将Int -> String
.bind(to: resultLabel.rx.text) // 绑定结果
.disposed(by: disposeBag)
小结
总的来说,这个例子是非常的简单的。只是由于刚上手,xcode提示的抽风,可能会造成些困扰。
检验篇
功能说明
- 监听username的长度是否大于5,否则pwd不可编辑
- 监听pwd的长度是否大于5
- 监听Do something的点击
- username和pwd的text长度没有大于5时,不可点击do something按钮
代码解释
总体来说,该Example的难度也不大,所以简单的说明下吧。
1、监听textFiled的长度是否大于指定的长度
let usernameValid = usernameTextField.rx.text.orEmpty
.map { (text) -> Bool in
text.characters.count > minimalUsernameLength
}.shareReplay(1)
let pwdValid = pwdTextField.rx.text.orEmpty
.map({ $0.characters.count > minimalPasswordLength })
.shareReplay(1)
这里的shareReplay可以使自己的订阅“重播”,但是每次是记得自己【订阅】的最后几次(取决于你传入的num)内容,从而减少map调用的次数。
官方注释:
Returns an observable sequence that shares a single subscription to the underlying sequence, and immediately upon subscription replays maximum number of elements in buffer.
2、监听按钮是否可点击
let everyThingValid = Observable.combineLatest(usernameValid, pwdValid) { (bool1, bool2) -> Bool in
return bool1 && bool2
}.shareReplay(1)
跟上篇的加法一样,使用到了combineLatest函数,将username和pwd的Bool监听结果,从而判断按钮是否可点击。
3、将监听的结果绑定UI
// 绑定
usernameValid.bind(to: pwdTextField.rx.isEnabled)
.addDisposableTo(disposeBag)
usernameValid.bind(to: usernameTipsLabel.rx.isHidden)
.addDisposableTo(disposeBag)
pwdValid.bind(to: pwdTipsLabel.rx.isHidden)
.addDisposableTo(disposeBag)
everyThingValid.bind(to: confirmButton.rx.isEnabled)
.addDisposableTo(disposeBag)
这里使用到时的bind函数,看一下官方注释:
/**
Creates new subscription and sends elements to observer.
In this form it's equivalent to `subscribe` method, but it communicates intent better, and enables
writing more consistent binding code.
- parameter to: Observer that receives events.
- returns: Disposable object that can be used to unsubscribe the observer.
*/
public func bind<O>(to observer: O) -> Disposable where O : ObserverType, O.E == Self.E
大概意思就说,将一个被观察者与一个指定的观察者进行绑定,被观察者事件流中发出的所有事件元素都会让观察者接收。
在MVVM中,该方法主要用于View和ViewModel之间的绑定。
4、监听按钮的点击
confirmButton.rx.tap
.subscribe(onNext: { [weak self] in
self?.showAlert()
})
.addDisposableTo(disposeBag)
看下官方定义
extension Reactive where Base: UIButton {
/// Reactive wrapper forTouchUpInside
control event.
public var tap: ControlEvent<Void> {
return controlEvent(.touchUpInside)
}
}
其实就是对touchUpInside的包装,那么按照以上的包装声明,我们也可以自己包装button的touchDown,touchUp等事件
小结
总的来说,这篇Example比起上一篇,稍微复杂了一点。其实不难看出,官方的Example在逐步的提高难度,并且慢慢地开始告诉你如何定制自己需要的Rx库。因此,我还是建议大家能够对官方Demo都过一篇,到时用的什么,都有个印象