RxSwift 开发技术文档
📌 概述
RxSwift 是面向 Swift 的函数响应式编程(Functional Reactive Programming)框架。它通过将异步事件抽象为可观察序列(Observable),实现跨线程调度、UI 绑定以及复杂逻辑的链式组合。
🛠 核心组件
1. 事件源 (Data Sources)
- Observable: 只读的事件流。最基础的序列。
- Subject: 既是 Observable 也是 Observer。常用于作为数据桥梁:
PublishSubject: 仅接收订阅之后的事件。BehaviorSubject: 必须有初始值,新订阅者会立刻收到最新的那个值。ReplaySubject: 缓存最后 $N$ 个事件,新订阅者能“回放”这些事件。
- Relay (RxCocoa): 对 Subject 的包装。不会发送
Error或Completed事件,专用于 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)
⚠️ 避坑指南与最佳实践
- 循环引用问题:在
subscribe(onNext:)闭包中使用self时,务必使用[weak self],否则会导致控制器无法释放。 - UI 必须在主线程:所有涉及 UI 绑定的链条,在最终
bind或subscribe之前,确保加上.observeOn(MainScheduler.instance)(或者直接使用 RxCocoa 的Driver机制,它自带主线程确保)。 - 不要漏掉
.disposed(by: disposeBag):如果忘记添加销毁袋,序列将永久常驻内存。
如果想继续完善这份文档,请告诉我您更希望深入哪部分:是 ViewModel (MVVM) 架构的实战组合,还是更高级的操作符(如 combineLatest, flatMap)解析?
发表回复