关于RxSwift的一点理解

Hello RxSwift!

这本书可以让你用Swift来编写响应式编程代码。但是到底什么是RxSwift,这里有很好的定义:

RxSwift是由可被观察的事件的异步队列和可操作的功能性的运算符组成的库,并且他可以由调度者通过参数的方式进行调度。

听起来很复杂?其实不用担心,因为无论是你编写响应式编程,还是理解他们背后的思想和一些相关的东西,官方通常都是用一些很吓人的术语来解释。尤其是当你第一次接触,或者是之前从未有人向你介绍过这些的时候,你就会觉得很可怕。

本书的目标就是带你逐步的去理解RxSwift的API,并且去运用每一个API,然后把它们运用到实际的iOSApp中。

你将会从RxSwift中最基本的功能开始,然后循序渐进的由中级到高级。花一些时间去广泛的理解里面的概念,这样以来读完本书后你就会精通RxSwift额思想和使用。其实Rx是非常广的话题,以至于不能单单通过这一本书来讲完,因此我们通过这本书让你对RX有一个坚实的了解,这样你就能继续提高自己的Rx水平了

其实我们并没有非常确信RxSwift的思想是什么,让我们在这个章节里面通过几个简单的例子来帮助我们理解响应式编程。

RxSwift本质其实就是当你的数据或者对象发生变化时候他会把这个变化放在一个单独的管道(队列)里面,以此来达到简化异步并发的过程的目的

这里打个比方一个按钮我点击了就会触发一个时间 那么我每点击一次就会生成一个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,这样就导致读懂并且书写这样的异步代码很难。可以看下下图:

我们来比较两个代码片段来总结下这章。一个是异步一个是同步。

同步代码

对数组的每个元素进行操作你应该很熟悉了吧,其实就是循环遍历嘛。这是一个非常简单而又坚实的功能,因为它保证了两件事:

  • 它是同步执行的。

  • 在循环遍历时候他是不可变的

花点时间想想这意味着什么。当你遍历一个数组的时候,你不需要检查所有的元素是否仍然存在,并且您不需要重新返回,以防另一个线程在集合的开始插入一个元素。您假定您总是在循环的开始时遍历整个集合。试试以下代码:

var array = [1, 2, 3]
for number in array {
print(number)
array = [4, 5, 6]
}
print(array)

最后的输出结果:

数组在for循环中是不可变的吗?执行顺序是什么?

异步代码

再考虑一个类似的代码,如下用户通过点击事件触发下面代码,每次点击都会输出数组下一个元素,然后用户重复点击直到把数组所有的元素输出完成:

var array = [1, 2, 3]
var currentIndex = 0

//this method is connected in IB to a button
@IBAction func printNext(_ sender: Any) {
print(array[currentIndex])

if currentIndex != array.count-1 {
currentIndex += 1
}
}

试想一下如果放在我们现实的App中真的可以这么执行吗?这个可说不准,因为如果在用户的两次点击之间又有其他的线程对这个数组进行了操作(增加、删除元素)那么数据就会发生错乱。而且如果currentIndex被另一个线程改变了那么你也不会得到预期的结果。

其实多线程最重要的就是数据争夺的问题,然而RxSwift很好的解决了这个问题

0%