RxSwift学习教程之基础篇

前言

我们在 iOS 开发过程中,几乎无时无刻都要面对异步事件的处理。例如,按键点击、数据保存、、音频后台播放、交互动画展示。这些事件并不具备特定时序性,甚至它们可能同时发生。

虽然 Apple 提供了通知、代理、GCD、闭包等异步机制,但是这些机制缺乏一个统一的抽象表述。另外,这些机制在处理共享的可变数据或状态时不够清晰简练。当然,这并不是说编写优雅的异步代码不现实。毕竟与其他平台相比 iOS 的异步机制还是很强大的。

幸运的是,我们能够通过 RxSwift 优雅的处理异步代码。

至于 RxSwift 的优势以及为什么要使用它,详见文档。这里就不废话了。

RxSwift 简介

其实响应式编程并不是一个什么新的概念,只不过是最近几年受到了开发者更多的关注。它最早由巨硬提出,主要的目的是为了应对复杂的 UI 异步事件和应用实时响应。社区中也已经有了各种语言版本的响应式编程实现,包括:RxJS、RxKotlin、Rx.NET、RxScala、RxSwift。这些类库仅仅只是实现方式存在差异,所以开发者在讨论应用逻辑时不会存在沟通障碍。

RxSwift 作为 Swift 语言的响应式编程实现,它在传统的命令式编程和纯函数式编程中找到了一个很好的平衡点。通过使用不可变代码定义异步处理输入,RxSwift 以一种确定可组合的形式对事件做出响应。

总的来说,RxSwift 有三个主要构成部分:Observable、Operator、Scheduler 。下面我们就来一一介绍。

Observable

Observable<T> 类可以说是 RxSwift 整个框架的基石。它能异步的触发一系列事件流并携带不可更改的状态变量。简单来说就是:它能让某个类的实例在一段时间内实现对另一个实例对象值的观察。例如:观察者可以捕获对所有可观察对象触发的事件,从而实现 UI 的实时更新或者是数据的实时处理。

其中 Observable<T> 类遵循了 ObservableType 协议。另外,Observable 对象所能触发的事件只有以下三种:

  • next 事件:该事件在触发时会将可观察对象的最新值传递给观察者。
  • completed 事件:该事件意味着可观察对象的生命周期正常结束不会在继续触发事件。
  • error 事件:该事件表明可观察对象出现了错误导致生命周期异常终止。

对于一个可观察的整型变量来说,异步环境下它所触发的事件可以在时间线上被描绘成这样一个事件序列:

另外,我们可以对这三类事件进行组合从而实现更为复杂的业务逻辑。与此同时,我们还可以使用该机制轻松实现代码解耦和多个对象间数据传递,无需编写代理或者闭包代码。

这里,我们还有一点值得注意。那就是可观察序列其实有两种类型。

有限观察序列( Finite observable sequences )

该序列是指那些最后会以 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<Data> 实例对象,并且在整个数据接收过程中会不断的触发 next 事件。然后,我们在 next 事件中会将这些片段数据保存到临时文件中。如果此过程出现错误的话,我们会将错误信息展示给用户。如果一切顺利我们会将临时文件保存到设备中。最后在下载完成后,我们可以在 completed 进行下一步的逻辑处理。

无限观察序列( Infinite observable sequences )

与网络任务不同的是,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! 。整个处理流程大致如下:

这种函数式的操作符让我们可以灵活的组合出更强大的功能。

Scheduler

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 的一些基本理念和构成,更多相关的内容将会在后面带来。

好了,以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家对我们的支持。

(0)

相关推荐

  • RxSwift学习之Observable的新建、订阅及取消订阅

    前言 我们在前一篇基础之上,本文将会介绍 RxSwift 中的 Observables 部分. 在 RxSwift 中 Observable 也被称为 Observable Sequence.Sequence.Stream.Observable 会以异步的方式不断的发射事件形成事件流,并且数据也会沿着事件流进行传播.下图是事件流的图像化表示: 其中从左到右的箭头代表时间轴,而三个圆圈则构成了可观察序列.而整个过程会按照从左到右的顺序.另外,事件可能在可观察序列生命周期内的任意时刻被触发. Obs

  • RxSwift学习教程之类型对象Subject详解

    前言 在上一篇文章我们介绍了 Observable 的基本概念和使用情形.但是大多数情形下,我们需要在应用运行时添加数据到 Observable 中并将其发送给订阅者.在这种需求场景下,我们就不得不使用 RxSwift 中另一种类型对象了 - Subject . 在应用中 Subject 实际上同时扮演了两个不同的角色:既是可观察对象同时也是观察者.这意味着 Subject 实例对象既可以接收事件也可以发送事件.例如,Subject 实例对象可以接收 next 事件信息,然后再将其发送给它自己的

  • RxSwift使用技巧之过滤操作详解

    前言 在前面的基础之上接下来我会介绍一些常用的函数和实用技巧.首先,本文将会介绍那些用于对 next 事件进行过滤的操作.这些过滤操作类似于 Swift 标准库中的 filter 操作.它能在我们开始真正进行业务处理前先把那些不符合条件的过滤掉,而且这种函数式编程的范式也能开阔我们的思维. Ignore 过滤 RxSwift 中最简单直接的过滤操作就是 ignoreElements 了.该操作会屏蔽所有的 next 事件,只会将注意力放在 error 和 completed 事件上.如下图所示,

  • RxSwift学习教程之基础篇

    前言 我们在 iOS 开发过程中,几乎无时无刻都要面对异步事件的处理.例如,按键点击.数据保存..音频后台播放.交互动画展示.这些事件并不具备特定时序性,甚至它们可能同时发生. 虽然 Apple 提供了通知.代理.GCD.闭包等异步机制,但是这些机制缺乏一个统一的抽象表述.另外,这些机制在处理共享的可变数据或状态时不够清晰简练.当然,这并不是说编写优雅的异步代码不现实.毕竟与其他平台相比 iOS 的异步机制还是很强大的. 幸运的是,我们能够通过 RxSwift 优雅的处理异步代码. 至于 RxS

  • seajs学习教程之基础篇

    介绍 众所周知前端开发模块化已经是大势所趋,目前模块化的规范有很多,众所周知的有commonJS,Module/Wrappings和AMD等,而且ES6也着手开始制定模块化机制的实现.类似于c/c++的include,java中的import关键字,在js中也定义了require关键字,用以引进依赖模块. 由于规范的多样性,模块化的实现也是各有各的不同. nodejs遵从的就是commonJS规范,它有着一些形式上的约定: 1.require为函数,该函数接受一个字符串作为模块标示符 2.req

  • kotlin 官方学习教程之基础语法详解

    kotlin 官方学习教程之基础语法详解 Google 在今天的举行了 I/O 大会,大会主要主要展示内有容 Android O(Android 8.0)系统.Google Assistant 语音助手.Google 智能音箱.人工智能.机器学习.虚拟现实等.作为一个 Android 开发者,我关心的当然是 Android O(Android 8.0)系统了,那么关于 Android O 系统的一个重要消息是全面支持 Kotlin 编程语言,使得 Kotlin 成为了 Android 开发的官方

  • 学习手册--Linux基础篇

    目录 1. Linux系统介绍 1.1 linux的概述 1.2 linux的优势 1.3 linux的分类 1.4 常见的发行版linux系统 2. Linux的安装 3. Linux的基础篇 3.1 目录结构 3.1.1 那具体有哪些呢? 3.1.2 需要特别知道的: 3.2 虚拟机之查看网络IP 3.2.1 查看网络IP 3.2.2 linux系统查看ip命令 3.2.3 在windows系统查看ip命令 3.2.4 在windows主机连接远程linux虚拟机系统测试 3.4 虚拟机之查

  • Netty学习教程之基础使用篇

    什么Netty? Netty是由JBOSS提供的一个java开源框架.Netty提供异步的.事件驱动的网络应用程序框架和工具,用以快速开发高性能.高可靠性的网络服务器和客户端程序. 也就是说,Netty 是一个基于NIO的客户.服务器端编程框架,使用Netty 可以确保你快速和简单的开发出一个网络应用,例如实现了某种协议的客户,服务端应用.Netty相当简化和流线化了网络应用的编程开发过程,例如,TCP和UDP的socket服务开发. 我们下面编写四个类 1.用于接收数据的服务器端Socket

  • PHP正则表达式完全教程之基础篇

    目前,正则表达式已经在很多软件中得到广泛的应用,包括*nix(Linux, Unix等),HP等操作系统,PHP,C#,Java等开发环境,以及很多的应用软件中,都可以看到正则表达式的影子. 正则表达式的使用,可以通过简单的办法来实现强大的功能. 为了简单有效而又不失强大,造成了正则表达式代码的难度较大,学习起来也不是很容易. 例子: ^.+@.+..+$ 这样的代码曾经多次把我自己给吓退过.可能很多人也是被这样的代码给吓跑的吧. 学习完本教程将让你也可以自由应用这样的代码. 正则表达式的历史

  • socket.io学习教程之基础介绍(一)

    前言 Web端与服务器间的实时数据传输的是一个很重要的需求,但最早只能通过AJAX轮询询实现.在WebSocket标准没有推出之前,AJAX轮询是唯一可行的方式(通过Flash浏览器也可以,但这里不做讨论).AJAX轮询原理是设置定时器,定时通过AJAX同步服务器数据.这种方式存在延时且对服务端造成很大负载.直到2011年,IETF才标准化WebSocket--一种基于TCP套接字进行收发数据的协议.现如今主流浏览器均已支持WebSocket. socket.io将数据传输部分独立出来形成了en

  • 传智播客学习之JavaScript基础篇

    一.JavaScript与java的区别 1.JavaScript是Netscape公司的产品,Java是Sun公司的产品. 2.JavaScript是基于对象,Java是面向对象. 3.JavaScript只需解释就可以执行,Java需要先编译成字节码文件,再执行. 4.JavaScript是弱类型,Java是强类型. 小结:其实java与JavaScript除了名字上有些像以外,然后JavaScript借用了部分java思想外,其余别的几乎没有什么关系. 二.如何将JavaScript与Ht

  • Python2.5/2.6实用教程 入门基础篇

    起步走 复制代码 代码如下: #! /usr/bin/python a=2 b=3 c="test" c=a+b print "execution result: %i"%c 知识点 Python是动态语言,变量不须预先声明. 打印语句采用C风格 字符串和数字 但有趣的是,在javascript里我们会理想当然的将字符串和数字连接,因为是动态语言嘛.但在Python里有点诡异,如下: 复制代码 代码如下: #! /usr/bin/python a=2 b="

随机推荐