Rx 记录

本文最后更新于 2021年4月4日 晚上

本文主要讲了一些关于 RxSwift 的基础内容. 比较杂…

Rx 记录

第一章是概述

第二章是 Observable, 讲了序列的各种创建方式, 以及三个特殊的 Observable: Single, Maybe, Completable

第三章是讲了四个重要的 Subject, Subject 是即可以用作 Observer, 因为可以向它们发送 onXXX 消息, 也可以作为 Observable 使用的类型, 这样就可以在它们上面动态添加元素, 而不用每次都去新建一个 Observable.

现在的情况下, 还需要多练习使用 Subject, 以及特殊的 Trait, 另外就是基本 Observable 的创建.

第五章开始就进入操作符的章节, 主要练习操作符的使用.

  • 忽略操作符:

    ignoreElements: 忽略所有元素, 只当结束的时候触发事件.

    elementAt: 只接收指定位置的元素. elementAt(2).

    filter: 指定条件忽略, 类似数组的过滤

  • skip 类操作符:

    skip: 跳过指定数量的元素

    skipWhile: 当不满足条件的时候均跳过, 遇到满足条件的元素后操作符便不再往后过滤.

    skipUntil: 一直跳过元素, 直到另外一个序列中产生一个元素. 之后就不再跳过了.

  • take 类操作符:

    take: 只取指定个数的元素

    takeWhile: 一直取元素,直到条件不满足.(若第一个就不满足,则不会取任何元素)

    takeUntil: 一直取元素, 直到另外一个序列发射元素为止.

  • Distinct 类操作符:

    distinctUntilChanged: 连续元素如果有连续相同的, 则这一段只取第一个元素.

  • 共享序列: share

    一般而言, 如果使用创建方法创建的 Observable, 在观察开始后, 都会新建一个完全独立的序列供观察者观察. 如果想要共享序列, 则需要使用 share 操作符, 保证多个观察是在同一序列上开展的.

一个清晰架构 + MVVM + RxSwift 工程的设计和施工记录

工程结构介绍

在这个工程中, 使用目前能够接触到的一些比较先进的施工和设计思想, 主要是清晰架构, MVVM, 以及 RxSwift 工具.

工程中分为如下 Target:

  • App 对应 target: 即表示层所在位置, 也是主要实现 MVVM 的地方.

  • Application: 业务逻辑层

  • Infrastructure: 网络通信层

  • Persistence: 数据持久层

  • Domain: APP 领域层, 定义对上层提供的接口以及层间交互的 DTO.

  • Common: 公共功能或配置信息所在层.

总体结构如下图所示:

如果是不想让 Rx 统治整个工程(以后很难更改), 则可以像下面这样:

或者按需将 Rx 引入到对应模块.

表示层施工技术

  1. 设置一个 ViewModelInputOutputTransformable 协议, 让所有的 ViewModel 来实现, 用于将 Input 转为 Output 供外界观察:
1
2
3
4
5
6
protocol ViewModelInputOutputTransformable {
associatedtype InputType
associatedtype OutputType

func transform(input: InputType) -> OutputType
}
  1. 设置一个 Bindable 协议, 让所有广义的视图去实现, 以统一广义视图的构造方式:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import UIKit

/// 可绑定协议
protocol Bindable {
associatedtype ViewModelType

/// 被绑定的 ViewModel
var viewModel: ViewModelType! { set get }

/// 对 ViewModel 的各项内容进行绑定操作, 外界不主动调用这个接口,
/// 而是通过调用 setViewModel(_ viewModel:) 在合适的时机(ViewDidLoad之后)自动执行这个接口的实现内容.
func bindUIWithViewModel()
}

/// MARK: - UIViewController 作为 Bindable 时的扩展
extension Bindable where Self: UIViewController {

/// 传入 ViewModel 并在恰当的时机后进行绑定.
///
/// - Parameter model: 需要绑定的 model.
mutating func setViewModel(_ viewModel: Self.ViewModelType) {
self.viewModel = viewModel
loadViewIfNeeded()
bindUIWithViewModel()
}
}
  1. 一个需要处理的问题: 具有 Associatedtype 的协议(泛型协议)作为类型如何使用? 这里由于 ViewModelInputOutputTransformable 是一个泛型协议, 故 View 在依赖 ViewModel 的时候使用的是具体类型, 下面先来构造 ViewModel:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
struct TodoItemsInput { 
//...
}

struct TodoItemsOutput {
//...
}

struct TodoItemsViewModel: ViewModelInputOutputTransformable {
func transform(input: TodoItemsInput) -> TodoItemsOutput {
let output =
// 构造 output 对象
//...
return output
}
}

在广义的 View 中, 像下面这样使用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class TodoItemsViewController: UIViewController, Bindable {

var viewModel: TodoItemsViewModel!

override func viewDidLoad() {
super.viewDidLoad()
}

// 含有具体的绑定代码, 自动会在 ViewDidLoad 后执行
func bindViewModel() {
let input = // 构造 input...
let output = viewModel.transform(input: input)
// 对 output 进行绑定...
}
}

需要在外部将依赖注入到视图中:

1
2
3
var todoItemsVC = TodoItemsViewController()
let todoItemsViewModel = TodoItemsViewModel()
todoItemsVC?.setViewModel(todoItemsViewModel)

广义视图中的实现如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import UIKit

class TodoItemsViewController: UIViewController, Bindable {

var viewModel: TodoItemsViewModel!

override func viewDidLoad() {
super.viewDidLoad()
}

// 含有具体的绑定代码, 自动会在 ViewDidLoad 后执行
func bindUIWithViewModel() {
print("可以开始绑定操作了: \(viewModel.debugDescription)")
// 将 input 转换为 output, 然后绑定到视图上.
}
}

Rx 实践

附录: 杂项

准备看 Swift 语言引导, 另外就是照着 Design Pattern 代码再敲几次.

探索 https://github.com/matteocrippa/awesome-swift 这里的东西.

准备 CollectionView 的内容: 专题来搞 CollectionView

正好引入 Carthage 依赖, 可以看看怎么弄文件列表: 直接写好文件名再把内容原样写到文件中即可.

遇到设置 @IBInspectable 的问题, 如何去设置并使用? 这个链接中去看看.

这里使用 Kingfisher 加载网络图片, 看看到时候写自适应的 item 如何操作.

ConcurrentDispatchQueueScheduler

SerialDispatchQueueScheduler

OperationQueueScheduler

GitHub 的 API 文档

基地址都是: https://api.github.com

且 V3 最好是携带这个 Header: Accept: application/vnd.github.v3+json

  • 用户仓库: /users/:username/repos

Rx 记录
https://blog.rayy.top/2018/09/15/2019-2-RxCleanArch/
作者
貘鸣
发布于
2018年9月15日
许可协议