RxSwift使用

RxSwift 开发技术文档

📌 概述

RxSwift 是面向 Swift 的函数响应式编程(Functional Reactive Programming)框架。它通过将异步事件抽象为可观察序列(Observable),实现跨线程调度、UI 绑定以及复杂逻辑的链式组合。


🛠 核心组件

1. 事件源 (Data Sources)

  • Observable: 只读的事件流。最基础的序列。
  • Subject: 既是 Observable 也是 Observer。常用于作为数据桥梁:
    • PublishSubject: 仅接收订阅之后的事件。
    • BehaviorSubject: 必须有初始值,新订阅者会立刻收到最新的那个值。
    • ReplaySubject: 缓存最后 $N$ 个事件,新订阅者能“回放”这些事件。
  • Relay (RxCocoa): 对 Subject 的包装。不会发送 ErrorCompleted 事件,专用于 UI 状态绑定。
    • PublishRelay / BehaviorRelay

2. 内存管理

  • DisposeBag: 订阅销毁袋。当页面(ViewController)销毁时,袋子内的所有订阅会自动断开,防止内存泄漏

🚀 核心使用场景与代码模板

场景 A:UI 事件监听与绑定 (RxCocoa)

将按钮点击、输入框输入等 UI 事件直接绑定到业务逻辑或另一个 UI 控件。

import UIKit
import RxSwift
import RxCocoa

class LoginViewController: UIViewController {
    @IBOutlet weak var usernameTextField: UITextField!
    @IBOutlet weak var loginButton: UIButton!
    
    private let disposeBag = DisposeBag()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // 示例 1: 输入字数限制与按钮状态联动
        usernameTextField.rx.text.orEmpty
            .map { $0.count >= 6 }                 // 转换成 Bool
            .bind(to: loginButton.rx.isEnabled)    // 直接绑定到按钮的启用状态
            .disposed(by: disposeBag)              // 自动加入销毁袋
            
        // 示例 2: 按钮点击事件响应
        loginButton.rx.tap
            .subscribe(onNext: { [weak self] in
                self?.executeLoginLogic()
            })
            .disposed(by: disposeBag)
    }
    
    private func executeLoginLogic() {
        print("开始登录...")
    }
}

场景 B:网络请求转换 (数据流映射)

利用操作符将原始网络请求结果转换成 UI 需要的模型。

import RxSwift

struct User: Codable {
    let name: String
}

class UserService {
    // 模拟网络请求:将回调封装为 Observable
    func fetchUser() -> Observable<Data> {
        return Observable.create { observer in
            let mockJson = "{\"name\": \"张三\"}".data(using: .utf8)!
            observer.onNext(mockJson)
            observer.onCompleted()
            return Disposables.create()
        }
    }
}

// 业务调用层
let service = UserService()
let bag = DisposeBag()

service.fetchUser()
    .map { data -> User in
        // 操作符:将 Data 解析为 Model
        return try JSONDecoder().decode(User.self, from: data)
    }
    .subscribe(onNext: { user in
        print("成功解析出用户: \(user.name)")
    }, onError: { error in
        print("错误处理: \(error)")
    })
    .disposed(by: bag)

场景 C:多线程调度 (Schedulers)

在后台处理耗时任务,在主线程更新 UI。

import RxSwift

someBackgroundHeavyTask()
    .subscribeOn(ConcurrentDispatchQueueScheduler(qos: .background)) // 1. 指定在后台线程执行任务
    .observeOn(MainScheduler.instance)                               // 2. 切换回主线程
    .subscribe(onNext: { result in
        // 3. 安全地更新 UI
        self.statusLabel.text = "处理完成: \(result)"
    })
    .disposed(by: disposeBag)

⚠️ 避坑指南与最佳实践

  1. 循环引用问题:在 subscribe(onNext:) 闭包中使用 self 时,务必使用 [weak self],否则会导致控制器无法释放。
  2. UI 必须在主线程:所有涉及 UI 绑定的链条,在最终 bindsubscribe 之前,确保加上 .observeOn(MainScheduler.instance)(或者直接使用 RxCocoa 的 Driver 机制,它自带主线程确保)。
  3. 不要漏掉 .disposed(by: disposeBag):如果忘记添加销毁袋,序列将永久常驻内存。

如果想继续完善这份文档,请告诉我您更希望深入哪部分:是 ViewModel (MVVM) 架构的实战组合,还是更高级的操作符(如 combineLatest, flatMap)解析

评论

《“RxSwift使用”》 有 1 条评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注