最近在写一个纯Swift的个人项目,使用了RxSwift这个函数式编程库,
踩了一些坑,写下备用。
1. Variable & combineLatest
var variablePayers: Variable<Array<PayPerson>>!
override func viewDidLoad() {
super.viewDidLoad()
//1. 检查输入金额是否正确
let moneyValid = paymentAmountInput.rx.text.orEmpty
.map { $0.tcz_isValidMoney() }
.shareReplay(1)
//2. 检查输入字符串长度
let payNameValid = payItemNameInput.rx.text.orEmpty
.map { $0.characters.count > 0 }
.shareReplay(1)
//3. 检查付款人数组
//variablePayers = Variable(payers)
//let payersValid = variablePayers.asObservable()
// .map { $0.count > 0 }
// .shareReplay(1)
let payersValid = Variable(payers).asObservable()
.map { $0.count > 0 }
.shareReplay(1)
//4. 合并检查所有条件是否都符合
let everythingValid = Observable.combineLatest(moneyValid, payNameValid, payersValid) { $0 && $1 && $2 }
everythingValid
.bindTo(addPaymentButton.rx.isEnabled)
.addDisposableTo(disposeBag)
}
上面代码的执行结果是everythingValid始终为true,debug后发现payersValid的状态是completed,而combineLatest函数只要发现其中一个信号是completed的,就直接为true了。那么为什么payersValid的状态不对呢?问题就出在Variable上,查看文档,描述如下
/// Variable is a wrapper for `BehaviorSubject`.
///
/// Unlike `BehaviorSubject` it can't terminate with error, and when variable is deallocated
/// it will complete it's observable sequence (`asObservable`).
原因就是Variable被释放后,会complete它的观察者队列。
查看代码
let payersValid = Variable(payers).asObservable()
.map { $0.count > 0 }
.shareReplay(1)
Variable(payers)的生命周期到viewDidLoad()后就结束了,这就是为什么payersValid的状态是completed的原因。
使用上面注释的代码段3,就可以解决这个问题。