一、Subject初探
在RxsWift中还有一种非常特殊的序列 Subject - 既是序列,也是观察者
,Subject是一个代理,它既是Observer,也是Observable .
1.Subject的五种类型
直接上例子:
// PublishSubject
// 1:初始化序列
let publishSub = PublishSubject<Int>() //初始化一个PublishSubject 装着Int类型的序列
// 2:发送响应序列
publishSub.onNext(1)
// 3:订阅序列
publishSub.subscribe { print("订阅到了:", $0) }
.disposed(by: disposbag)
// 再次发送响应
publishSub.onNext(2)
publishSub.onNext(3)
print("********** BehaviorSubject **********")
// BehaviorSubject
// 1:创建序列
let behaviorSub = BehaviorSubject.init(value: 100)
// 2:发送信号
behaviorSub.onNext(2)
behaviorSub.onNext(3)
// 3:订阅序列
behaviorSub.subscribe{ print("订阅到了1:", $0) }
.disposed(by: disposbag)
// 再次发送
behaviorSub.onNext(4)
behaviorSub.onNext(5)
// 再次订阅
behaviorSub.subscribe{ print("订阅到了:", $0) }
.disposed(by: disposbag)
print("********** ReplaySubject **********")
// ReplaySubject
// 1:创建序列
let replaySub = ReplaySubject<Int>.create(bufferSize: 2)
// let replaySub = ReplaySubject<Int>.createUnbounded()
// 2:发送信号
replaySub.onNext(1)
replaySub.onNext(2)
replaySub.onNext(3)
replaySub.onNext(4)
// 3:订阅序列
replaySub.subscribe{ print("订阅到了:", $0) }
.disposed(by: disposbag)
// 再次发送
replaySub.onNext(7)
replaySub.onNext(8)
replaySub.onNext(9)
print("********** AsyncSubject **********")
// AsyncSubject
// 1:创建序列
let asynSub = AsyncSubject<Int>.init()
// 2:发送信号
asynSub.onNext(1)
asynSub.onNext(2)
// 3:订阅序列
asynSub.subscribe{ print("订阅到了:", $0) }
.disposed(by: disposbag)
// 再次发送
asynSub.onNext(3)
asynSub.onNext(4)
asynSub.onCompleted()
print("********** Variable **********")
// Variable : 5.0已经废弃(BehaviorRelay 替换) - 大家可以了解一下
// 1:创建序列
let variableSub = BehaviorRelay.init(value: 1)
// 2:发送信号
variableSub.accept(100)
variableSub.accept(10)
// 3:订阅信号
variableSub.asObservable().subscribe{ print("订阅到了:", $0) }
.disposed(by: disposbag)
print("打印:\(variableSub.value)")
// 再次发送
variableSub.accept(1000)
查看运行结果:
PublishSubject
:可以不需要初始值来进行初始化(也就是可以为空),并且它只会向订阅者发送在订阅之后才接收到的元素。BehaviorSubject
:通过一个默认初始值来创建,当订阅者订阅BehaviorSubject时,会收到订阅后Subject上一个发出的Event,如果还没有收到任何数据,会发出一个默认值
,之后就和PublishSubject一样,正常接收新的事件。ReplaySubject
:ReplaySubject发送源Observable的所有事件,无论observer什么时候开始订阅。bufferSize: 2 在订阅之前保留2次。AsyncSubject
:AsyncSubject只发送由源Observable发送的最后一个事件,并且只在源Observable完成之后(如果源Observable没有发生任何值,AsyncSubject也不会发送任何值)。BehaviorRelay-Variable
:替换原来的Variable,可以存储一个信号,随时订阅响应,behaviorRelay.accept(20)。(后面废弃是因为,违背了响应式编程)
- 首先他们都是
Observable
,他们的订阅者都能收到他们发出的新的Event
。 - 直到
Subject
发出.complete
或者.error
的Event
后,该Subject
便终结了,同时它也就不会再发出.next
事件。 - 对于那些在
Subject
终结后再订阅他的订阅者,也能收到subject
发出的一条.complete
或.error
的event
,告诉这个新的订阅者它已经终结了。 - 他们之间最大的区别只是在于:当一个新的订阅者刚订阅它的时候,能不能收到
Subject
以前发出过的旧Event
,如果能的话又能收到多少个。
2.Subject的绑定/传值
我们通过一个实战例子来学习:
var modelsSub: BehaviorSubject<[LGModel]>? //定义BehaviorSubject
//初始化BehaviorSubject
override func viewDidLoad() {
super.viewDidLoad()
setupUI()
modelItems = LGCacheManager.manager.fetchLGModelData()
modelsSub = BehaviorSubject(value: modelItems) //设置默认值-重启app时选中状态
modelsSub?.subscribe(onNext: { items in
self.modelItems = items
self.tableView.reloadData()
LGCacheManager.manager.updateAllData(models: items)
self.deleteBtn.isEnabled = !items.isEmpty
let num = items.filter { model in
!model.isFinished
}.count
self.navigationItem.rightBarButtonItem?.isEnabled = num < 6
self.title = num == 0 ? "RxSwiftDemo" : "还有\(num)条待办事项"
}).disposed(by: disposeBag)
}
订阅绑定items消息,更新updateAllData 数据,isFinished 查询完成数量。更新UI等操作。
@objc func didClickAddAction() {
let newRowIndex = modelItems.count
let model = LGModel(title:"我是一条数据:\(Date().timeIntervalSince1970)", isFinished: false)
modelItems.append(model)
modelsSub?.onNext(modelItems)
}
添加一条数据,或者发送onnext模型消息。
extension LGViewController: UITableViewDelegate {
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
// 点击选择就是删除
// 处理数据
modelItems.remove(at: indexPath.row)
modelsSub?.onNext(modelItems)
tableView.deselectRow(at: indexPath, animated: true)
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
let model = modelItems[indexPath.row]
model.toggleFinished()
modelsSub?.onNext(modelItems)
}
}
点击选择改变cell model状态,及删除功能。都是通过向BehaviorSubject发送.onNext(modelItems)消息。
传值:
fileprivate func pushToDetailVC(model: LGModel?) {
let sb = UIStoryboard(name: "Main", bundle: nil)
detailVC = (sb.instantiateViewController(withIdentifier: "LGDetailViewController") as! LGDetailViewController)
if let m = model {
detailVC?.model = m
}
detailVC?.todoOB.subscribe(onNext: { item in
self.modelItems.append(item)
self.modelsSub?.onNext(self.modelItems)
}).disposed(by: disposeBag)
navigationController?.pushViewController(detailVC!, animated: true)
}
外部订阅的方式(LGDetailViewController):
fileprivate let todoSubject = PublishSubject<LGModel>() //私有
var todoOB: Observable<LGModel> {//外界只有订阅的权利,里面才能响应
todoSubject.asObservable()
}