零基础也能看懂的 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 的文本框改变(DelegateKVONSNotificationCenteraddTarget)。
  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 的文本框改变(DelegateKVONSNotificationCenteraddTarget)。
  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 的注册界面。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,491评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,856评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,745评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,196评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,073评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,112评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,531评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,215评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,485评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,578评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,356评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,215评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,583评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,898评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,497评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,697评论 2 335

推荐阅读更多精彩内容

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