Examples
计算变量
首先,让我们从一些必要的代码开始。
这个例子的目的是如果条件满足,将 a 和 b 计算后的值绑定到 c 上。
下面就是必要的代码示例:
// this is standard imperative codevar c: Stringvar a = 1 // this will only assign the value `1` to `a` oncevar b = 2 // this will only assign the value `2` to `b` onceif a + b >= 0 {c = "\(a + b) is positive" // this will only assign the value to `c` once}
c 现在的值是 3 is positive。然而,如果我们改变了 a 的值为 4, c 依然还是老的值。
a = 4 // `c` will still be equal to "3 is positive" which is not good// we want `c` to be equal to "6 is positive" since 4 + 2 = 6
这并不是想要的行为。
下面是使用 RxSwift 改进逻辑后的代码:
let a /*: Observable<Int>*/ = Variable(1) // a = 1let b /*: Observable<Int>*/ = Variable(2) // b = 2// combines latest values of variables `a` and `b` using `+`let c = Observable.combineLatest(a.asObservable(), b.asObservable()) { $0 + $1 }.filter { $0 >= 0 } // if `a + b >= 0` is true, `a + b` is passed to the map operator.map { "\($0) is positive" } // maps `a + b` to "\(a + b) is positive"// Since the initial values are a = 1 and b = 2// 1 + 2 = 3 which is >= 0, so `c` is initially equal to "3 is positive"// To pull values out of the Rx `Observable` `c`, subscribe to values from `c`.// `subscribeNext` means subscribe to the next (fresh) values of `c`.// That also includes the initial value "3 is positive".c.subscribeNext { print($0) } // prints: "3 is positive"// Now, let's increase the value of `a`a.value = 4 // prints: 6 is positive// The sum of the latest values, `4` and `2`, is now `6`.// Since this is `>= 0`, the `map` operator produces "6 is positive"// and that result is "assigned" to `c`.// Since the value of `c` changed, `{ print($0) }` will get called,// and "6 is positive" will be printed.// Now, let's change the value of `b`b.value = -8 // doesn't print anything// The sum of the latest values, `4 + (-8)`, is `-4`.// Since this is not `>= 0`, `map` doesn't get executed.// This means that `c` still contains "6 is positive"// Since `c` hasn't been updated, a new "next" value hasn't been produced,// and `{ print($0) }` won't be called.
简单 UI 绑定
- 不绑定数值,让我们用
UITextField的rx_text绑定数值 - 然后,使用
map把String转换到Int并且使用异步 API 判断这个数字是否是素数 - 如果文本在异步调用完成之前改变了,一个新的异步调用会通过
concat代替他 - 将结果绑定到
UILabel
let subscription/*: Disposable */ = primeTextField.rx_text // type is Observable<String>.map { WolframAlphaIsPrime(Int($0) ?? 0) } // type is Observable<Observable<Prime>>.concat() // type is Observable<Prime>.map { "number \($0.n) is prime? \($0.isPrime)" } // type is Observable<String>.bindTo(resultLabel.rx_text) // return Disposable that can be used to unbind everything// This will set `resultLabel.text` to "number 43 is prime? true" after// server call completes.primeTextField.text = "43"// ...// to unbind everything, just callsubscription.dispose()
这个例子中使用的所有操作符是和第一个例子中使用的操作相同的。
自动完成
如果你是 Rx 的新手,那么下面的例子在一开始可能会有一点点难以应对。但是这被用来展示 RxSwift 的代码在真实世界如何被看待。
这个例子包含复杂的异步 UI 进度通知验证逻辑。当 disposeBag 被释放时,所有操作符会被取消。
让我们赶快来看一下代码:
// bind UI control values directly// use username from `usernameOutlet` as username values sourceself.usernameOutlet.rx_text.map { username in// synchronous validation, nothing special hereif username.isEmpty {// Convenience for constructing synchronous result.// In case there is mixed synchronous and asynchronous code inside the same// method, this will construct an async result that is resolved immediately.return Observable.just((valid: false, message: "Username can't be empty."))}// ...// User interfaces should probably show some state while async operations// are executing.// Let's assume that we want to show "Checking availability" while waiting for a result.// Valid parameters can be:// * true - is valid// * false - is not valid// * nil - validation pendingtypealias LoadingInfo = (valid: String?, message: String?)let loadingValue : LoadingInfo = (valid: nil, message: "Checking availability ...")// This will fire a server call to check if the username already exists.// Its type is `Observable<ValidationResult>`return API.usernameAvailable(username).map { available inif available {return (true, "Username available")}else {return (false, "Username already taken")}}// use `loadingValue` until server responds.startWith(loadingValue)}// Since we now have `Observable<Observable<ValidationResult>>`// we need to somehow return to a simple `Observable<ValidationResult>`.// We could use the `concat` operator from the second example, but we really// want to cancel pending asynchronous operations if a new username is provided.// That's what `switchLatest` does..switchLatest()// Now we need to bind that to the user interface somehow.// Good old `subscribeNext` can do that.// That's the end of `Observable` chain..subscribeNext { valid inerrorLabel.textColor = validationColor(valid)errorLabel.text = valid.message}// This will produce a `Disposable` object that can unbind everything and cancel// pending async operations.// Instead of doing it manually, which is tedious,// let's dispose everything automagically upon view controller dealloc..addDisposableTo(disposeBag)
这代码是最简单的。仓库中还有很多其他的例子,所以尽情查看他们吧。
这些例子包含如何使用 Rx 在 MVVM 设计模式的上下文,或者没有 MVVM。
