在 iOS 开发过程当中,咱们几乎无时无刻都要面对异步事件的处理。例如,按键点击、数据保存、、音频后台播放、交互动画展现。这些事件并不具有特定时序性,甚至它们可能同时发生。html
虽然 Apple 提供了通知、代理、GCD、闭包等异步机制,可是这些机制缺少一个统一的抽象表述。另外,这些机制在处理共享的可变数据或状态时不够清晰简练。固然,这并非说编写优雅的异步代码不现实。毕竟与其余平台相比 iOS 的异步机制仍是很强大的。git
幸运的是,咱们可以经过 RxSwift 优雅的处理异步代码。github
至于 RxSwift 的优点以及为何要使用它,详见文档。这里就不废话了。编程
其实响应式编程并非一个什么新的概念,只不过是最近几年受到了开发者更多的关注。它最先由巨硬提出,主要的目的是为了应对复杂的 UI 异步事件和应用实时响应。社区中也已经有了各类语言版本的响应式编程实现,包括:RxJS、RxKotlin、Rx.NET、RxScala、RxSwift。这些类库仅仅只是实现方式存在差别,因此开发者在讨论应用逻辑时不会存在沟通障碍。swift
RxSwift 做为 Swift 语言的响应式编程实现,它在传统的命令式编程和纯函数式编程中找到了一个很好的平衡点。经过使用不可变代码定义异步处理输入,RxSwift 以一种肯定可组合的形式对事件作出响应。bash
总的来讲,RxSwift 有三个主要构成部分:Observable、Operator、Scheduler 。下面咱们就来一一介绍。服务器
Observable
其中 Observable
对于一个可观察的整型变量来讲,异步环境下它所触发的事件能够在时间线上被描绘成这样一个事件序列:架构
另外,咱们能够对这三类事件进行组合从而实现更为复杂的业务逻辑。与此同时,咱们还可使用该机制轻松实现代码解耦和多个对象间数据传递,无需编写代理或者闭包代码。
这里,咱们还有一点值得注意。那就是可观察序列其实有两种类型。
该序列是指那些最后会以 completed 或者 error 事件终极生命周期的可观察对象。最典型的例子就是,经过 API 进行网络请求:
下面是一个文件下载请求的 Rx 范式的代码:
API.download(file: "http://www...")
.subscribe( onNext: { data in
append data to temporary file },
onError: { error in
display error to user },
onCompleted: {
use downloaded file })复制代码
这段代码中 API.download (file:) 函数会建立一个 Observable 实例对象,而且在整个数据接收过程当中会不断的触发 next 事件。而后,咱们在 next 事件中会将这些片断数据保存到临时文件中。若是此过程出现错误的话,咱们会将错误信息展现给用户。若是一切顺利咱们会将临时文件保存到设备中。最后在下载完成后,咱们能够在 completed 进行下一步的逻辑处理。
与网络任务不一样的是,UI 以及交互事件是无限观察序列。它们并不存在一个明确的生命周期终结点。例如,针对可能的设备方向旋转,咱们须要实时进行布局修改。而设备的方向旋转自己是随机发生的而且与应用自己具备一样的生命周期。所以 Rx 也须要一种机制支持这种无限观察序列。
针对这种状况,在 RxSwift 中咱们能够经过如下代码来应对:
UIDevice.rx.orientation.subscribe(onNext: { current in
switch current {
case .landscape:
re-arrange UI for landscape
case .portrait:
re-arrange UI for portrait
}
})复制代码
ObservableType 以及 Observable 类的实现中都包含大量的异步处理方法,这些方法也被称为操做符。因为这些操做符只是进行异步输入处理并产生对应输出,因此它并不会对应用产生多余的反作用。另外,由于操做符之间的高度解耦因此咱们很容易对它进行组合以期实现复杂的功能。
例如,对于上面的设备方向旋转,咱们能够对全部的状况进行过滤而后对部分值进行进一步处理。
UIDevice.rx.orientation
.filter { value in
return value != .landscape
}
.map { _ in
return "Portrait is the best!"
}
.subscribe( onNext: { string in
showAlert(text: string)
})复制代码
上面的代码中,咱们首先会将全部 .landscape 方向过滤掉不作任何处理。而后,咱们再将剩下的 portrait 转化为字符串 Portrait is the best! 。整个处理流程大体以下:
这种函数式的操做符让咱们能够灵活的组合出更强大的功能。
Schedulers 是一个与 GCD 相对应的概念,只不过前者使用起来更为方便。RxSwift 中预约义的 Schedulers 足够开发者应对绝大多数的编程场景。
例如,咱们可使用串型序列 SerialDispatchQueueScheduler 来处理 next 事件,经过 ConcurrentDispatchQueueScheduler 运行并行文件下载任务,经过 OperationQueueScheduler 运行一个 NSOperationQueue 操做队列。甚至你能够在同一个观察对象的不一样任务中使用不一样的 Schedulers 类型,以下图:
咱们将左侧的任务用不一样的颜色加以区分,而后在右侧任务被拆分为不一样的步骤而且放在不一样 Schedulers 中。例如,network subscription 任务就被拆分为三个步骤并依次放入了 Custom NSOperation Scheduler 、Background Concurrent Scheduler、Main Thred Serial Scheduler 。
值得注意的是, RxSwift 并无对客户端的应用架构做出硬性规定。这意味着,咱们能够在已有项目中引入 RxSwift 进行响应式编程实践。固然已有框架中一定存在一个最适合 RxSwift 的,而它就是 MVVM。由于在 MVVM 中咱们能够将 VM 中的部分属性直接与 UI 进行绑定。
另外,对于 iOS 编程来讲仅仅有 RxSwift 是远远不够的。RxSwift 只是 Swift 语言的响应式实现,咱们还须要一种 Cocoa 层面的实现。好在这里存在 RxCocoa 做为 UIKit 的响应式补充。前面设备方向代码 UIDevice.rx.orientation 就是 RxCocoa 的应用 。
做为系列开篇,本文介绍了 RxSwift 的一些基本理念和构成,更多相关的内容将会在后面带来。
原文地址