RxSwift文档十一(示例)

代码下载

示例

响应值

首先,从一些命令式代码开始。此示例的目的是如果满足某些条件将从a,b中计算的的值绑定到标识符c。

以下是计算c值的命令性代码:

// 这是标准的命令式代码
var c: String
var a = 1       // 这只会将值“ 1” 值赋给“a”一次
var b = 2       // 这只会将值“2”值赋给“b”一次

if a + b >= 0 {
    c = "\(a + b) is positive" // 这只会将值赋给“ c ”一次
}

c的值现在是正数3。但是,如果更改a的值为4,c仍将存储旧值。

a = 4 // `c`仍将等于“3 is positive”,这是不好的,希望`c`等于“6 is positive”,因为4 + 2 = 6

这不是理想的行为。

这是使用RxSwift的改进逻辑:

let a /*: Observable<Int>*/ = BehaviorRelay(value: 1)   // a = 1
let b /*: Observable<Int>*/ = BehaviorRelay(value: 2)   // b = 2

// 通过组合操作符计数a + b
let c = Observable.combineLatest(a, b) { $0 + $1 }
	.filter { $0 >= 0 }               // 如果 `a + b >= 0` 为真, `a + b`通过map操作符
	.map { "\($0) is positive" }      // maps `a + b` 为 "\(a + b) is positive"

// 自从初始化a = 1和b = 2
// 1 + 2 = 3 值 >= 0, 因此`c`初始值等于"3 is positive"

// 要从Rx`Ibservable``c`中提取值,请订阅`c`中的值。
// `subscribe(onNext:)`表示订阅`c`的下一个(新的)值。
// 还包括初始值“3 is positive”。
c.subscribe(onNext: { print($0) })          // 打印"3 is positive"

// 现在,增加`a`的值
a.accept(4) 
// 最新值的总和,`4`和`2`,现在是`6`。
// 由于这是`>= 0`,`map`运算符产生“6 is positive正” 
// 结果被“赋值”给`c`。
// 由于`c`的值改变了,`{print($ 0)}`将被调用,
// 将打印“6 is positive”。

// 现在改变`b`的值
b.accept(-8)                                 // 不打印任何东西
// 最新值的总和,`4 +( -  8)`,是`-4`。
// 因为这不是`> = 0`,所以`map`不会被执行。
// 这意味着`c`仍然包含“6为正” 
// 由于`c`尚未更新,因此尚未生成新的“next”值,
// 和`{print($ 0)}`不会被调用。

简单的UI绑定

let subscription/*: Disposable */ = primeTextField.rx.text      // 类型是Observable <String>
            .map { WolframAlphaIsPrime(Int($0) ?? 0) }          // 类型是Observable <Observable <Prime >>
            .concat()                                           // 类型是Observable <Prime>
            .map { "number \($0.n) is prime? \($0.isPrime)" }   // 类型是Observable<String>
            .bind(to: resultLabel.rx.text)                        // 返回Disposable解除绑定

// 将设置`resultLabel.text`为"number 43 is prime? true" 然后调用completes. 手动触发控制事件,因为这是RxCocoa能观察到的UIKit事件
primeTextField.text = "43"
primeTextField.sendActions(for: .editingDidEnd)

// ...

// 解除绑定
subscription.dispose()

代码分析:

  • 不是绑定到Relays,而是使用rx.text绑定UITextField属性值。
  • 接下来,map将String转换为Int并使用异步API确定是否是素数。
  • 如果在异步调用完成之前更改了文本,则新的异步调用将通过concat替换它。
  • 将结果绑定到UILabel。

本例中使用的所有操作符与第一个示例中使用的操作符相同。没什么特别的。

自动输入验证

如果是Rx的新手,下一个例子起初可能会有点压力。但是,它是为了演示RxSwift代码在现实中的表现。

此示例包含具有进度通知的复杂异步UI验证逻辑。disposeBag销毁时,所有操作都将被取消。

试一试:

enum Availability {
    case available(message: String)
    case taken(message: String)
    case invalid(message: String)
    case pending(message: String)

    var message: String {
        switch self {
        case .available(let message),
             .taken(let message),
             .invalid(let message),
             .pending(let message): 

             return message
        }
    }
}

// 直接绑定UI控件值
// 使用`usernameOutlet`中的用户名作为用户名值源
self.usernameOutlet.rx.text
    .map { username -> Observable<Availability> in

        // 同步验证,这里没什么特别的
        guard let username = username, !username.isEmpty else {
            // 方便构建同步结果。
            // 如果在同一个方法内部有混合的同步和异步代码,这将构造一个立即解析的异步结果。
            return Observable.just(.invalid(message: "Username can't be empty."))
        }

        // ...

        // 用户界面应该在异步操作时显示某些状态
        // 正在执行
        let loadingValue = Availability.pending(message: "Checking availability ...")

        // 这将触发服务器调用以检查用户名是否已存在。
        // 它的类型是`Observable <Bool>`
        return API.usernameAvailable(username)
          .map { available in
              if available {
                  return .available(message: "Username available")
              }
              else {
                  return .taken(message: "Username already taken")
              }
          }
          // 使用`loadingValue`直到服务器响应
          .startWith(loadingValue)
    }
// 因为现在有了`Observable <Observable <Availability >>` 
// 需要以某种方式返回一个简单的`Observable <Availability>`。
// 可以使用`concat`操作符如第二个例子,但如果真的想提供一个新的用户名,取消挂起的异步操作。
// 这就是`switchLatest`的作用。
    .switchLatest()
// 现在需要以某种方式将其绑定到用户界面。
// 好`subscribe(onNext :)可以做到这一点。
// 于是'Observable`链的结束。
    .subscribe(onNext: { [weak self] validity in
        self?.errorLabel.textColor = validationColor(validity)
        self?.errorLabel.text = validity.message
    })
// 这将生成一个`Disposable`对象,可以取消绑定所有内容并取消挂起的异步操作。
// 而不是手动执行,这很乏味,
// 让在视图控制器dealloc上自动处理所有内容。
    .disposed(by: disposeBag)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值