超详细!RxSwift 中的 BehaviorRelay 使用教程(含原理 + 示例 + 实战)
目录
前言
1.什么是 BehaviorRelay
2.基本使用方式
3.BehaviorRelay的常用API
4.BehaviorRelay 和其它类型的对比
5.BehaviorRelay的使用场景
1.绑定UITableView
2.MVVM 场景下使用 BehaviorRelay
6.使用注意事项以及建议
1.注意事项
2.使用建议总结
7.推荐阅读
前言
在 iOS 开发中,使用 RxSwift 构建响应式架构(如 MVVM)越来越流行。我们经常会遇到“需要持有某个状态值,并且随时通知观察者”的需求,这时你会发现 BehaviorRelay 几乎无处不在。
今天这篇文章,我们就来深入剖析 BehaviorRelay 是什么、怎么用、适合用在什么场景中,以及实战中的最佳实践。
1.什么是 BehaviorRelay
BehaviorRelay 是 RxCocoa 中封装的一个类,用于代替旧版的 Variable(已废弃)。它有以下几个特点:
-  持有当前值,可以通过 .value 获取 
-  可以更新值,使用 .accept(_:) 方法 
-  可以对外暴露为Observable 
-  不会发送 error或completed,所以永远不会中断 
本质上,它是对 RxSwift 的 BehaviorSubject 的一个安全封装,去掉了 .onError() 和 .onCompleted(),适合用作状态容器。
2.基本使用方式
import RxSwift
import RxCocoalet disposeBag = DisposeBag()// 1. 创建一个初始值为 0 的 BehaviorRelay
let relay = BehaviorRelay<Int>(value: 0)// 2. 订阅它
relay.asObservable().subscribe(onNext: { value inprint("当前值:\(value)")}).disposed(by: disposeBag)// 3. 修改它的值
relay.accept(1)  // 输出:当前值:1
relay.accept(5)  // 输出:当前值:53.BehaviorRelay的常用API
| API | 说明 | 
|---|---|
| .value | 当前持有的值(同步获取) | 
| .accept(_:) | 接受一个新值,会触发订阅回调 | 
| .asObservable() | 转为只读的 Observable,防止外部直接修改 | 
| .bind(to:) / .drive(_:) | 可以与 UI 控件绑定 | 
4.BehaviorRelay 和其它类型的对比
| 特性 | BehaviorRelay | PublishRelay | BehaviorSubject | 
|---|---|---|---|
| 持有当前值 | ✅ 是 | ❌ 否 | ✅ 是 | 
| 获取当前值 | ✅ .value | ❌ 无 | ✅ .value | 
| 是否可变 | ✅ .accept() | ✅ .accept() | ✅ .onNext() | 
| 是否会终止 | ❌ 不会 | ❌ 不会 | ✅ .onCompleted() 或 .onError() | 
| 推荐场景 | 状态管理 | 事件传递 | 不推荐直接使用(易误用) | 
5.BehaviorRelay的使用场景
1.绑定UITableView
let items = BehaviorRelay<[String]>(value: ["苹果", "香蕉", "橘子"])items.bind(to: tableView.rx.items(cellIdentifier: "cell")) { row, element, cell incell.textLabel?.text = element}.disposed(by: disposeBag)// 添加新元素
var current = items.value
current.append("榴莲")
items.accept(current)  // 表格会自动刷新✅ BehaviorRelay 是 TableView/CollectionView 数据源绑定的理想选择。
2.MVVM 场景下使用 BehaviorRelay
在MVVM架构中,我们常常把 BehaviorRelay 放到 ViewModel 中作为状态容器:
class ContactListViewModel {let contacts = BehaviorRelay<[String]>(value: [])func addContact(_ name: String) {var list = contacts.valuelist.append(name)contacts.accept(list)}
}ViewController 中绑定:
viewModel.contacts.bind(to: tableView.rx.items(cellIdentifier: "cell")) { row, name, cell incell.textLabel?.text = name}.disposed(by: disposeBag)6.使用注意事项以及建议
1.注意事项
-  不要滥用 .accept(),应限制数据修改权限在 ViewModel 或管理器中 
-  .value 是同步获取,不会触发订阅回调 
-  若只需要事件传递(如点击),请用 PublishRelay,不要用 BehaviorRelay 
-  BehaviorRelay 永远不会发送 .completed 或 .error,也无法手动终止它 
2.使用建议总结
| 场景 | 是否推荐使用 BehaviorRelay | 
|---|---|
| 表示状态(布尔、列表、数值等) | ✅ 推荐 | 
| 控制 UI 状态(按钮是否可点等) | ✅ 推荐 | 
| 事件传递(点击事件、跳转等) | ❌ 不推荐 → 用 PublishRelay | 
| 需要流结束、错误处理的场景 | ❌ 不适合 → 用 Observable 或 Subject | 
7.推荐阅读
-  RxSwift 官方文档 
-  RxCocoa BehaviorRelay 源码 
