RxSwift可观察序列

在 RxSwift(以及 ReactiveX 体系)中,“Observable” 并不是唯一的可观察序列类型。为了更精确地表达不同场景下的事件流语义(比如是否只发一个值、是否带初始值、是否重放历史等),RxSwift 提供了 多种 Observable 的变体或子类型。

下面我们将系统讲解 RxSwift 中常见的 可观察序列类型(Observable-like types),包括:

  • Observable
  • Single
  • Maybe
  • Completable
  • Driver
  • Signal
  • 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:

特性 Driver Signal
Replay 历史 ✅ 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()

七、最佳实践建议

  1. 优先使用语义明确的类型(如 Single 而非 Observable)可减少 bug。
  2. UI 绑定尽量用 Driver/Signal,避免线程错误和崩溃。
  3. 不要在 Driver/Signal 中放入可能出错的逻辑,提前用 catch 处理。
  4. Driver 适合表示“状态”,Signal 适合表示“事件” —— 这是 RxCocoa 的设计哲学。

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容