在 RxSwift(以及 ReactiveX 体系)中,“Observable” 并不是唯一的可观察序列类型。为了更精确地表达不同场景下的事件流语义(比如是否只发一个值、是否带初始值、是否重放历史等),RxSwift 提供了 多种 Observable 的变体或子类型。
下面我们将系统讲解 RxSwift 中常见的 可观察序列类型(Observable-like types),包括:
ObservableSingleMaybeCompletableDriverSignal-
SharedSequence(Driver和Signal的基类)
并结合具体例子说明它们的区别、适用场景和使用方式。
一、基础:Observable<Element>
✅ 特点:
- 可以发射 0 到多个
.next事件 - 可以以
.error或.completed结束 - 是最通用、最灵活的类型
📌 适用场景:
- 不确定数据数量(如网络流、用户输入、传感器数据)
- 需要处理错误或多次更新
🔧 示例:
let numbers = Observable.of(1, 2, 3)
numbers.subscribe { event in
print(event)
}
// next(1)
// next(2)
// next(3)
// completed
二、单一结果类型(Single-Value Types)
这些类型用于明确语义:只关心“成功/失败”,且最多只发一个值。
1. Single<Element>
✅ 特点:
- 只能发射一个值,然后立即完成
- 事件只有两种可能:
.success(value).failure(error)
- 不能发出多个值,也不能只完成不发值
📌 适用场景:
- 网络请求(如登录、获取用户信息)
- 一次性操作(如保存到数据库)
🔧 示例:
func fetchUser(id: Int) -> Single<User> {
return Single.create { single in
api.getUser(id) { result in
switch result {
case .success(let user):
single(.success(user))
case .failure(let error):
single(.failure(error))
}
}
return Disposables.create()
}
}
fetchUser(id: 123)
.subscribe(
onSuccess: { user in print("User: \(user.name)") },
onError: { error in print("Error: \(error)") }
)
.disposed(by: bag)
💡 相当于
Observable<User>+ 保证只发一个值 + 无 completed 事件。
2. Maybe<Element>
✅ 特点:
- 可能发射 0 个或 1 个值,然后完成
- 三种结局:
-
.success(value)→ 有值 -
.completed→ 无值但正常结束 -
.error(error)→ 出错
-
📌 适用场景:
- 查询缓存(可能命中,可能未命中)
- 可选结果的操作(如查找数据库记录)
🔧 示例:
func findCachedUser(id: Int) -> Maybe<User> {
return Maybe.create { maybe in
if let user = cache[id] {
maybe(.success(user))
} else {
maybe(.completed) // 没找到,但不是错误
}
return Disposables.create()
}
}
findCachedUser(id: 123)
.subscribe(
onSuccess: { user in print("Found: \(user)") },
onError: { error in print("Cache error: \(error)") },
onCompleted: { print("Not found in cache") }
)
✅ 对比
Single:Maybe允许“无结果但成功”。
3. Completable
✅ 特点:
- 不发射任何值
- 只有两种结局:
.completed.error(error)
📌 适用场景:
- 删除操作、上传完成通知、无返回值的任务
🔧 示例:
func deleteUser(id: Int) -> Completable {
return Completable.create { completable in
api.deleteUser(id) { result in
switch result {
case .success:
completable(.completed)
case .failure(let error):
completable(.error(error))
}
}
return Disposables.create()
}
}
deleteUser(id: 123)
.subscribe(
onCompleted: { print("Deleted successfully") },
onError: { error in print("Delete failed: \(error)") }
)
✅ 语义清晰:只关心“是否完成”,不关心“返回什么”。
三、UI 安全类型(RxCocoa 提供)
这些类型自动在主线程运行,永不抛出错误,适合绑定 UI。
4. Driver<Element>
✅ 特点:
- 永不失败(no error)
- 自动在 MainScheduler 上观察(线程安全)
- 共享副作用(share(replay: 1, scope: .whileConnected))
- 必须有初始值(replay 1)
📌 适用场景:
- 绑定到 UI 控件(如 label.text、tableView.items)
- 表示“当前状态”(如用户名、开关状态)
🔧 示例:
let username = textField.rx.text.orEmpty
.map { "Hello, \($0)" }
.asDriver(onErrorJustReturn: "Hello, Guest") // 转为 Driver
username
.drive(label.rx.text) // drive 代替 bind(to:)
.disposed(by: bag)
✅
Driver保证:
- 不会 crash(错误被处理)
- 总在主线程更新 UI
- 新订阅者立即收到最新值
5. Signal<Element>
✅ 特点:
- 永不失败
- 自动在 MainScheduler 上观察
- 共享副作用(share(scope: .whileConnected))
- 不 replay 历史值(只发新事件)
📌 适用场景:
- 事件流(如按钮点击、通知)
- 不需要初始值,只响应“新动作”
🔧 示例:
let buttonTapSignal = button.rx.tap
.map { "Button tapped at \(Date())" }
.asSignal(onErrorJustReturn: "Error")
buttonTapSignal
.emit(to: messageLabel.rx.text) // emit 代替 subscribe
.disposed(by: bag)
✅ 对比
Driver:
特性 DriverSignalReplay 历史 ✅ replay(1) ❌ 不重放 用途 状态(当前值) 事件(新动作) 初始值 必须有 可无
四、对比总结表
| 类型 | 发射值数量 | 是否可 error | 是否主线程 | 是否共享 | 是否 replay | 典型用途 |
|---|---|---|---|---|---|---|
Observable |
0~N | ✅ | ❌ | ❌ | ❌ | 通用流 |
Single |
1 | ✅ | ❌ | ❌ | ❌ | 一次性请求(成功/失败) |
Maybe |
0 or 1 | ✅ | ❌ | ❌ | ❌ | 可选结果查询 |
Completable |
0 | ✅ | ❌ | ❌ | ❌ | 无返回值任务 |
Driver |
0~N | ❌ | ✅ | ✅ | ✅ (1) | UI 状态绑定 |
Signal |
0~N | ❌ | ✅ | ✅ | ❌ | UI 事件流 |
五、如何选择?
-
网络请求有返回值? →
Single -
网络请求可能无结果? →
Maybe -
只是执行一个操作? →
Completable -
绑定 label / tableView? →
Driver -
监听按钮点击 / 通知? →
Signal - 不确定?先用
Observable,再根据语义优化
六、相互转换示例
// Observable → Driver(需处理错误 + 指定 scheduler)
let driver = observable
.observeOn(MainScheduler.instance)
.catchAndReturn("Fallback")
.asDriver()
// Observable → Signal
let signal = observable
.observeOn(MainScheduler.instance)
.catch { _ in Observable.empty() }
.asSignal(onErrorJustReturn: ())
// Single → Observable
let obs = single.asObservable()
七、最佳实践建议
-
优先使用语义明确的类型(如
Single而非Observable)可减少 bug。 -
UI 绑定尽量用
Driver/Signal,避免线程错误和崩溃。 -
不要在
Driver/Signal中放入可能出错的逻辑,提前用catch处理。 -
Driver适合表示“状态”,Signal适合表示“事件” —— 这是 RxCocoa 的设计哲学。