RxSwift 介绍
RxSwift 介绍
https://beeth0ven.github.io/RxSwift-Chinese-Documentation/
https://medium.com/@DianQK/rxswift-%E4%BB%8B%E7%BB%8D-ce078367c42a
RxSwift 是在 Apple 推出 Swift 后, ReactiveX 推出 Reactive Extensions 系列一个实现库。但是学习 RxSwift 不是学习如何使用第三方库,而是学习一个思想。
可能很多人都听说过函数式编程(Functional Programming)、响应式编程(Reactive Programming)、函数响应式编程(Functional Reactive Programming)。又听说过 ReactiveCocoa 这个库。RxSwift 与之基本上相近。笔者更倾向于把 RxSwift 当作一个响应式编程的工具。
那么什么是响应式?笔者将以 RxSwift 为例介绍响应式编程的相关知识。
响应式编程
笔者在这里不得不先阐述一个事实响应式的思考真的很难,特别是从面向对象以及命令式编程迁移过来。
但是不用害怕,一切都会随着时间的推移而逐渐明朗起来。
事实上关于响应式编程有多种解释,Wikipedia 上的解释过于抽象、理论,不适用于实践上。而最先推出 Rx 的微软给出的解释是 Rx = Observables + LINQ + Schedulers 笔者将在本章一步一步的解释 Rx 是什么。
通俗一些的解释就是面向异步数据流编程。数据流可以有多种形式,比如读取一个文件、进行一个网络请求、用户出发的行为等等,都可以认为是一种数据流。当然一个变量也可以认为是一种数据流。
而 Rx 强大之处就是:合并函数,操作和变换事件流。
我们先来理解一下这个数据流是指什么,以点击 Button 事件,我们打算记录点击的次数,并打印出来:

这幅图描述了用户间断的点击一个 Button 场景,也就是说在时间上产生了多个点击 Button 的事件,这一个个点击事件构成了这个点击事件流。这个事件流是可以传递的,在传递的同时可以进行一些变换。
所以接下来我们应该做的是将点击变换成 1 ,后面我们将这一个个的 1 叠加起来就完成了上面的事情。

通过 Rx 提供的 map 方法,可以将 () 变换成 1 ,即:
.map { return 1 }
接下来我们需要将这些 1 收集并累加起来,Rx 为我们提供了一个 scan 的方法

这里 scan 的实现是返回上一次的值与当前传递的值之和。这里的逻辑就类似于 Swift 中的 reduce :
let result = [1, 1, 1, 1].reduce(0) { acc, x in return acc + x }
将上面的流程连起来:

最终流程就是这个样子:

而这就是一个事件流的传递。
最后一步就是订阅整个事件的结果。

我们可以通过一个 subscribeNext 完成这件事:
.subscribeNext { value in
print(value)
}
完整的代码如下:
button
.rx_tap
.map { return 1 }
.scan(0) { acc, x return acc + x }
.subscribeNext { value in
print(value)
}
当然这里可能有一个比较有意思的事情要思考,如果我们想打印这样的结果呢?
"当前点击次数:1 。"
"当前点击次数:2 。"
"当前点击次数:3 。"
"当前点击次数:4 。"
可以这样写:
.subscribeNext { value in
print("当前点击次数:\(value) 。")
}
当然还有一种方式:
button
.rx_tap
.map { return 1 }
.scan(0) { acc, x return acc + x }
.map { value in return "当前点击次数:\(value) 。" }
.subscribeNext { value in
print(value)
}
此时我想我们可以回顾一下不用 Rx 要如何写:
private var tapCount = 0
override func viewDidLoad() {
super.viewDidLoad()
button.addTarget(
self
, action: #selector(CalculateButtonWithoutRxViewController.buttonTap(_:))
, forControlEvents: .TouchUpInside
)
dynamic private func buttonTap(sender: UIButton) {
tapCount += 1
let result = "当前点击次数:\(tapCount) 。"
print(result)
}
对比上面的这两段代码,笔者认为用响应式编程更能清晰的表述代码逻辑。到目前为止,响应式编程可以做如下理解:
Observer 通过订阅 Observable ,当产生变化时,Observable 会通知 Observer ,并将变化描述的信息告诉 Observer 。此外在这个通知的传递过程中,Rx 提供了诸如 map 、scan 等多种方法,方便使用者对描述的信息进行加工,从而得到最终想要的值。

Pull 和 Push
命令式编程就是 Pull ,而响应式编程是 Push 。
在命令式下,我们通过调用一个方法的形式获取一个数据,这个数据可能是一个 Model 、一个状态、一个 UITextField 的输入的文本 text 。这就是一个 Pull 模型,在需要的时候拉取对应的数据。
guard let text = textField.text else { return nil }
// 根据 text 进行各种处理
这就好比阅读一些优秀的博客,在想阅读的时候,打开博客网址,确认下有没有新的内容,如果有,就阅读学习一下。
而响应式的 Push 类似于订阅了该博客的 RSS ,当有更新的时候,推送给你,然后你再来决定读与不读。这就不需要我们每次都去检查一下博客状态,只需要等待更新的推送。
Rx 系列通过可观察序列 Observable 和观察者 Observer 两个类实现 Push 模型。Observer 订阅 Observable ,Observable 发送值给它的订阅者们,也就是通知所有的订阅者 Observer - 我想把这个值发给你,然后你看着处理吧。
Observer 通常都是以 closure 形式存在的,来看一个简单的例子:
为了更好的描述这一订阅关系,示例代码选择了 PublishSubject 代替 Observable ,我们将在 Subject 章节解释什么是 PublishSubject ,与 Observable 的关系。这里你可以把它当作一个 Observable 。
let intSequence = PublishSubject<Int>()
intSequence
.subscribeNext { value in
print("当前值为:\(value) 。")
}
// --------- 分割线 ----------
intSequence.onNext(1)
intSequence.onNext(2)
intSequence.onNext(3)
这段代码描述了 Observer 订阅了一个 intSequence ,intSequence 可能会发出一些 Int 。在建立了这样的一个订阅关系后,intSequence 推送了 1 、 2 、 3 三个值。输出结果就是:
当前值为:1 。
当前值为:2 。
当前值为:3 。
回顾一下记录 Button 点击次数的代码,不用 Rx 的部分代码如下:
dynamic private func buttonTap(sender: UIButton) {
tapCount += 1
let result = "当前点击次数:\(tapCount) 。"
print(result)
}
在 buttonTap 这个 Selector 中,每次都对 tapCount 加 1 ,然后打印加 1 后的 tapCount 。这里就存在一个 Pull ,每次都要主动获取 tapCount 的值,同时进行 tapCount = tapCount + 1 。
而使用 Rx 的代码:
button
.rx_tap
.map { return 1 }
.scan(0) { acc, x return acc + x }
.map { value in return "当前点击次数:\(value) 。" }
.subscribeNext { value in
print(value)
}
则是在收到 tap 点击的推送,将推送的值进行变换,并传递下去,最终在 subscribeNext 中根据收到的结果打印当前结果。
RxSwift 介绍的更多相关文章
- ReactiveX序列——RxSwift 浅析
ReactiveX序列——RxSwift Swift是苹果公司新推出的一门现代化的编程语言,并且将其开源出来了,Swift具有很多的优点,这也使得这门语言推出的短时间引起了很大反应的原因,在最近的 ...
- RxSwift 系列(九) -- 那些难以理解的概念
前言 看完本系列前面几篇之后,估计大家也还是有点懵逼,本系列前八篇也都是参考RxSwift官方文档和一些概念做的解读.上几篇文章概念性的东西有点多,一时也是很难全部记住,大家脑子里面知道有这么个概念就 ...
- 大神都在看的RxSwift 的完全入坑手册
大神都在看的RxSwift 的完全入坑手册 2015-09-24 18:25 CallMeWhy callmewhy 字号:T | T 我主要是通过项目里的 Rx.playground 进行学习和了解 ...
- RxSwift 函数响应式编程
Max 在 Boston 上学,在 San Francisco 工作,是一名软件工程师及创业者.当他还在高中的时候就在一家创业公司工作了,他非常喜欢使用 iOS.Android 以及 JavaScri ...
- RxSwift之路 1#Swift语法知识准备
RxSwift之路 1#Swift语法知识准备 在开始学习 RxSwift 之前,一定要对 Swift 相关语法有所了解,否则就很难理解为什么可以这样.关于 Swift 的学习其实只要看看 Swift ...
- RxSwift学习笔记7:buffer/window/map/flatMap/flatMapLatest/flatMapFirst/concatMap/scan/groupBy
1.buffer的基本使用 let publishSubject = PublishSubject<String>() //buffer 方法作用是缓冲组合,第一个参数是缓冲时间,第二个参 ...
- RxSwift之路 2#如何开始
RxSwift之路 2#如何开始 第一步当然是把项目clone到本地,github地址:https://github.com/ReactiveX/RxSwift. 官方文档 学习的第一手资源当然是项目 ...
- RxSwift学习笔记1:RxSwift的编程风格
第一天:简单体验与RxSwift的编程风格 import UIKit//导入Rx相关框架 import RxSwift import RxCocoa struct Music { let name:S ...
- RxSwift 系列(九)
前言 看完本系列前面几篇之后,估计大家也还是有点懵逼,本系列前八篇也都是参考RxSwift官方文档和一些概念做的解读.上几篇文章概念性的东西有点多,一时也是很难全部记住,大家脑子里面知道有这么个概念就 ...
随机推荐
- 【java】Java相关学习参考链接(持续更新)
How to do in java,https://howtodoinjava.com/,Java手册,分版本,并且有每个版本的新特性的详细解析. Java World,https://www.jav ...
- 基于Python+Django重定向的例子
Django源码, 这里HttpResponseRedirect和HttpResponsePermanentRedirect没有太大差别,前者是返回302临时重定向,后者返回301永久重定向 clas ...
- 常用的js正则验证整理
一.校验数字的js正则表达式 1 数字:^[0-9]*$ 2 n位的数字:^\d{n}$ 3 至少n位的数字:^\d{n,}$ 4 m-n位的数字:^\d{m,n}$ 5 零和非零开头的数字:^(0| ...
- 模块度Q
模块度:也称模块化度量值,是目前常用的一种衡量网络社区结构强度的方法. 常用语衡量一个社区划分结果的优劣:一个理想化的社区划分应该对应着社区内部节点间相似度尽可能的高,同时社区外部节点间的相异度尽可能 ...
- 记一次Nginx+Keepalived高可用故障转移
Master端:192.168.2.156 ! Configuration File for keepalived global_defs { notification_email { acassen ...
- 蓝桥杯 倍数问题(dfs,枚举组合数)
标题:倍数问题 [题目描述]众所周知,小葱同学擅长计算,尤其擅长计算一个数是否是另外一个数的倍数.但小葱只擅长两个数的情况,当有很多个数之后就会比较苦恼.现在小葱给了你 n 个数,希望你从这 n 个数 ...
- 关于python3.6上传文件时报错:HTTPSConnectionPool(host='***.org', port=443): Max retries exceeded with url: /post (Caused by SSLError(SSLError(1, '[SSL: CERTIFICATE_VERIFY_FAIL解决办法
第一个报错: 最近在练习post请求中上传文件时遇到了一个奇葩事情,两台电脑上写了一模一样的代码,一个运行正常,另一个一片红. 最后了解了一下原因以及解决办法.先记录下关键代码: files = {& ...
- Microsoft Office Word 中的公式自动编号
先插入公式,#,插入题注(交叉引用),生成了标号.此时整个公式是题注样式.在公式和标号之间插入一个样式分隔符. ____________________________________________ ...
- JS对象与原型链
每个函数都存在一个prototype的属性,然后这个属性值为一个对象,我们称之为原型对象 每个对象都存在着一个隐藏的属性"__proto__" 这个属性引用了创建这个对象的函数的p ...
- jsp填坑:找不到属性
javax.el.PropertyNotFoundException: Property [***] not found on type 接手的项目的页面是用jsp写的,虽然再有十几天就2019年了, ...