# Hello RxSwift!
这本书可以让你用 Swift 来编写响应式编程代码。但是到底什么是 RxSwift, 这里有很好的定义:
<font color=orange>RxSwift 是由可被观察的事件的异步队列和可操作的功能性的运算符组成的库,并且他可以由调度者通过参数的方式进行调度。</font> <br>
听起来很复杂?其实不用担心,因为无论是你编写响应式编程,还是理解他们背后的思想和一些相关的东西,官方通常都是用一些很吓人的术语来解释。尤其是当你第一次接触,或者是之前从未有人向你介绍过这些的时候,你就会觉得很可怕。
本书的目标就是带你逐步的去理解 RxSwift 的 API,并且去运用每一个 API,然后把它们运用到实际的 iOSApp 中。
你将会从 RxSwift 中最基本的功能开始,然后循序渐进的由中级到高级。花一些时间去广泛的理解里面的概念,这样以来读完本书后你就会精通 RxSwift 额思想和使用。其实 Rx 是非常广的话题,以至于不能单单通过这一本书来讲完,因此我们通过这本书让你对 RX 有一个坚实的了解,这样你就能继续提高自己的 Rx 水平了
其实我们并没有非常确信 RxSwift 的思想是什么,让我们在这个章节里面通过几个简单的例子来帮助我们理解响应式编程。
<font color=orange>RxSwift 本质其实就是当你的数据或者对象发生变化时候他会把这个变化放在一个单独的管道 (队列) 里面,以此来达到简化异步并发的过程的目的 </font><br>
这里打个比方一个按钮我点击了就会触发一个时间 那么我每点击一次就会生成一个 Action 我们用一个管道去装在这些 Action,每加一个 Action 就会把他放管道里面,我们可以理解为管道里面流动的 Actions,且管道与管道之间相互独立。同理我们可以吧 Button 改成一个 UITExtField,Action 就是每一次输入事件。
作为一个 iOS 的开发者我相信这已经很好帮你去理解什么是 RxSwift 了吧,这应该是比你在一开始看到的那些专业术语好理解的多。
如果你还是不清楚,那么你至少应该理解,RxSwift 可以很轻松的帮你编写异步操作的代码,你要知道编写异步操作的代码是比较难的,所以所任何一点点的帮助都是受大家所欢迎的。
# 异步编程的介绍
如果你想用一种通俗简单的语言来描述异步编程,比如你在做一个 iSO 的 App,那么你一定想到如下几个东西:
接受 Button 的点击事件
当 text field 的 Action 和键盘的弹出和收起动画之间的关系
从网上下载大图片
往硬盘里面存数据
播放视频
以上的所有东西看似是发生在同一时刻其实真的是吗?我们思考一个问题:比如你在看视频,这时候你点击了 textfield 弹出键盘,大家都知道键盘由下往上弹出是有一个动画的,就算键盘已经出现到了屏幕上,只要动画没有做完你的视频就不会暂停,真的是这样吗,内部又是如何实现的?如下图:
程序里面不同的部分不会阻塞彼此的执行,iOS 提供了几种 API,通过多核 CPU 来在不同的线程上进行不同的工作。
其实编写真正并行的代码其实是很复杂的,打个比方假如两个线程同时访问同一个资源,就会产生资源争夺的问题,比如谁先访问,谁后访问。
# UIKit 中的一些异步的 API
苹果在 iOS SDK 中提供了很多 api,帮助你编写异步代码。你在你的项目中使用过这些但是可能还没有考虑过它们,因为它们是编写移动应用程序的基础。毕竟苹果爸爸封装好的,我们拿来用就好了,干嘛想那么多。
你一定用过以下几点
NotificationCenter
delegate
Grand Central Dispatch(GCD)
Closures(Block)
由于大部分的类都是异步的,并且 UI 在内部也是异步的,所以很难去猜测整个程序的执行顺序,因此你的 APp 会因为一些外部的原因而表现不同,比如用户的输入不同、网络环境的不同、或者一些其他的东西。用户每次在打开你的 APp 其实代码的执行顺序都是不同的 (当然除了一些自动化测试的场景,那些条件都是预先设置好的。)
其实写好异步代码并不是绝对不可能的,毕竟苹果给我提供了非常强大的 API,相比较于其他平台这要好很多。不过问题在于编写复杂的异步代码很难,部分原因是因为苹果给我们提供了大量的 SDK,而且他们并不统一。如果使用 delegate 我们需要遵循特制的格式,block,NotificationCenter 等等都是这样的,所以并没有一种通用的、贯穿所有异步方法的 API,这样就导致读懂并且书写这样的异步代码很难。可以看下下图:
我们来比较两个代码片段来总结下这章。一个是异步一个是同步。
# 同步代码
对数组的每个元素进行操作你应该很熟悉了吧,其实就是循环遍历嘛。这是一个非常简单而又坚实的功能,因为它保证了两件事:
它是同步执行的。
在循环遍历时候他是不可变的
花点时间想想这意味着什么。当你遍历一个数组的时候,你不需要检查所有的元素是否仍然存在,并且您不需要重新返回,以防另一个线程在集合的开始插入一个元素。您假定您总是在循环的开始时遍历整个集合。试试以下代码:
1 | var array = [1, 2, 3] |
最后的输出结果:
数组在 for 循环中是不可变的吗?执行顺序是什么?
# 异步代码
再考虑一个类似的代码,如下用户通过点击事件触发下面代码,每次点击都会输出数组下一个元素,然后用户重复点击直到把数组所有的元素输出完成:
1 | var array = [1, 2, 3] |
试想一下如果放在我们现实的 App 中真的可以这么执行吗?这个可说不准,因为如果在用户的两次点击之间又有其他的线程对这个数组进行了操作 (增加、删除元素) 那么数据就会发生错乱。而且如果 currentIndex 被另一个线程改变了那么你也不会得到预期的结果。
其实多线程最重要的就是数据争夺的问题,然而 RxSwift 很好的解决了这个问题