零基础也能看懂的 RxSwift 官方 Example 解析(1) Bindings

概述

很多小伙伴在初学 RxSwift 时,在面对大量的操作符和各种抽象的概念时可能都会感到无从下手,但其实官方提供的 Example 就能够很方便的帮助我们学习 RxSwift 的各种概念以及如何与 MVVM 相结合。毕竟直接看实际的运用场景比看抽象的概念要容易理解的多。

我个人认为 RxSwift 的核心其实很简单,就是把要操作的事件、属性都抽象成一个个Observable,剩下的变换、组合、过滤、响应(订阅)、线程调度、生命周期管理都是你对 Observable 的加工和处理。如果你真的理解了什么是 Observable,哪些东西可以被包装成 Observable 那么你已经成功了一半啦,就像你刚学面向对象编程,搞懂了什么是对象,哪些东西可以被抽象成对象以后,后面的学习是不是顺利了很多呢。

其实初学的时候真的不用在面对大量的操作符时困惑,也不要有怕难的心态,觉得这么多东西我得记到什么时候。可以先看一遍文档有能力的也可以看看源码。用的多了你会发现和我们平常写代码一样,常用的 Api 就那些,其他用的少的真忘记的时候再翻翻文档就好。(中文文档 RxSwift-Chinese-Documentation)

好了废话不多说,本篇所有示例代码在 RxSwift 官方项目中就有,下载完了直接运行即可。

可以看到官方为我们分了三块内容,

  • iPhone Example
  • TableView 和 CollectionView Example
  • 综合的 Example

本篇文章我们先从这些 Demo 里最简单的 Bindings 说起。

Adding numbers

先看运行效果

有三个 UITextField 任何一个 UITextField 输入内容时,把三者相加,在最底部 UILabel 显示结果。

这是一个很简单的响应式编程的例子,这个页面主要由四个元素组成

@IBOutlet weak var number1: UITextField!
@IBOutlet weak var number2: UITextField!
@IBOutlet weak var number3: UITextField!
@IBOutlet weak var result: UILabel!

先考虑一下以往我们会怎么实现:

  1. 监听三个 UITextField 的文本框改变(Delegate、KVO、NSNotificationCenter、addTarget)。
  2. 在回调方法中将三个 UITextField 输入内容转成 Int 相加并赋值给 UILabel。

原生实现最大的问题在于,无论哪种方式,监听文本框内容改变的代码都不是那么的优雅。

看一下用 RxSwift 如何实现。回想我们刚刚所说的核心,把属性或者事件抽象成 Observable,再对 Observable 进行操作。

  1. 包装 (把三个 UITextField 输入的内容抽象成三个 Observable)
number1.rx.text.orEmpty
number2.rx.text.orEmpty
number3.rx.text.orEmpty
  1. 组合 (把三个Observable组合,并将每一个值转成 Int 类型相加)。
Observable.combineLatest(number1.rx.text.orEmpty, number2.rx.text.orEmpty, number3.rx.text.orEmpty) { textValue1, textValue2, textValue3 -> Int in
    return (Int(textValue1) ?? 0) + (Int(textValue2) ?? 0) + (Int(textValue3) ?? 0)
 }

文档中为我们描述的 combineLatest 的作用。

当多个 Observables 中任何一个发出一个元素,就发出一个元素。这个元素是由这些 Observables 中最新的元素,通过一个函数组合起来的。


说的再直白一点就是,这三个 UITextField 任意一个有新值的时候都会被组合成新的Observable。

  1. 转换 (把 Int 类型转换成 String 类型)
.map { $0.description }
  1. 响应 (把值绑定到 UILabel)
.bind(to: result.rx.text)
  1. 管理生命周期
.disposed(by: disposeBag)

怎么样是不是很简单呢,只需要6行代码我们就完成了这个需求。

SimpleValidation

运行效果


  • 当用户输入用户名时,如果用户名不足 5 个字就显示红色提示语,并且无法输入密码,当用户名符合要求时才可以输入密码。
  • 同样的当用户输入的密码不到 5 个字时也显示红色提示语。
  • 当用户名和密码有一个不符合要求时底部的绿色按钮不可点击,只有当用户名和密码同时有效时按钮才可点击。
  • 当点击绿色按钮后弹出一个提示框

页面由以下元素组成

/// 用户名
@IBOutlet weak var usernameOutlet: UITextField!
/// 用户名红色提示语
@IBOutlet weak var usernameValidOutlet: UILabel!

/// 密码
@IBOutlet weak var passwordOutlet: UITextField!
/// 密码红色提示语
@IBOutlet weak var passwordValidOutlet: UILabel!
/// 按钮
@IBOutlet weak var doSomethingOutlet: UIButton!

还是先考虑一下以往我们会怎么实现:

  1. 监听两个 UITextField 的文本框改变(Delegate、KVO、NSNotificationCenter、addTarget)。
  2. 在回调方法中判断用户名是否符合要求,用判断结果去设置提示语是否隐藏和密码框是否可以输入。
  3. 在回调方法中判断密码是否符合要求,用判断结果去设置提示语是否隐藏。
  4. 拿到前两个判断的结果,当前两个的结果都为真时,按钮可以点击。
  5. 添加按钮点击事件。

看一下用 RxSwift 如何实现。还是我们刚刚所说的核心,把属性或者事件抽象成 Observable,再对 Observable 进行操作。

  1. 用户名格式是否正确 (变换)
let usernameValid = usernameOutlet.rx.text.orEmpty
.map { $0.count >= minimalUsernameLength }
.share(replay: 1)
  1. 密码格式是否正确 (变换)
let passwordValid = passwordOutlet.rx.text.orEmpty
 .map { $0.count >= minimalPasswordLength }
 .share(replay: 1)
  1. 两者都正确(组合 ,combineLatest 作用上面介绍过,再巩固一下)
let everythingValid = Observable.combineLatest(usernameValid, passwordValid) { $0 && $1 }
.share(replay: 1)

这里你可能比较疑惑这个 .share(replay: 1) 是干嘛的。

通俗一点说,当有多个订阅者去订阅同一个 Observable 的时候,我们不希望 Observable 每次有新的订阅者都去执行。

  1. 响应
usernameValid
.bind(to: passwordOutlet.rx.isEnabled)
.disposed(by: disposeBag)
usernameValid
.bind(to: usernameValidOutlet.rx.isHidden)
.disposed(by: disposeBag)
passwordValid
.bind(to: passwordValidOutlet.rx.isHidden)
.disposed(by: disposeBag)
everythingValid
.bind(to: doSomethingOutlet.rx.isEnabled)
.disposed(by: disposeBag)

由于 .share(replay: 1) 的存在,这个判断密码或者用户名是否合法的操作,不管以后被多少人订阅,只会判断一次,这样可以避免不必要的资源消耗。

  1. 按钮添加点击事件
doSomethingOutlet.rx.tap
.subscribe(onNext: { [weak self] _ in self?.showAlert() })
.disposed(by: disposeBag)

当然这步我们是可以通过扩展的方式让他更加优雅的,这篇我们不做过多讲解。

最后说句题外话,学东西还是要从简单的学起,这样会多一些正面积极的反馈,就像是打游戏总会一段时间就有一个小的奖励,刺激你继续玩下去。如果一上来就看大量的操作符,各种概念和源码,挫败感一大就不想学了。

下一篇将更新如何与 MVVM 结合做一个 GitHub 的注册界面。

最后编辑于 :
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • 前言RxSwift的目的是让数据/事件流和异步任务能够更方便的序列化处理,能够使用Swift进行响应式编程。 本文...
    努力奔跑的小男孩阅读 2,032评论 0赞 3
  • 概述 RxSwift顾名思义是Swift的一种框架,您或许曾经听说过「响应式编程」(Reactive Progra...
    Mr大喵喵阅读 2,039评论 3赞 4
  • 今天是星期六,如果不算今天的话,开学已经一周了,时间过得真快啊!我很怀念这一周的生活,从进教室那一刻起……我发现整...
    依卓1阅读 338评论 0赞 2
  • “我已经老了。”小说的开篇如是写道。 翻开书,眼前渐渐显现出这样一幅画面,风烛残年、容颜备受岁月摧残的老人在昏黄的...
    夜雨灯下客阅读 577评论 0赞 3
  • 第八篇(周末回家) 小耀英和妈妈乘车到学校以后,耀英很快便找到了自己的宿舍和班级位置,然后妈妈帮着小耀英把被子...
    MrYichen阅读 246评论 0赞 0

友情链接更多精彩内容