RxSwift(3.4.1)- Subjects

来源:互联网 发布:java小游戏超级玛丽 编辑:程序博客网 时间:2024/06/07 23:21

什么是Subject

subjects充当了观察者序列和观察者。(Subjects act as both an observable and an observer)。它们既可以接受事件也可以进行订阅。subject接受.next事件,每次接收到事件,都会发送给他的订阅者(subscriber)。subject也可以订阅一个或者多个观察者序列。

Subject的类型

RxSwift中有4种类型的subject,分别是PublishSubject、ReplaySubject、BehaviorSubject、Variable :
 
PublishSubject:开始的时候是空的,只发送新的元素给观察者。它仅仅会发送observer订阅之后的事件,也就是说如果sequence上有.Next的到来,但是这个时候某个observer还没有subscribe它,这个observer就收不到这条信息,它只会收到它订阅之后发生的事件。

ReplaySubject:初始化指定一个缓冲大小(buffer size),并且将持有缓冲大小的元素发送给新的观察者(订阅者)。它和PublishSubject不同之处在于它不会漏消息。即使observer在subscribe的时候已经有事件发生过了,它也会收到之前的事件序列。

BehaviorSubject:开始的时候有初始值,并且重新发送它或者最新的元素给新的观察者。当有observer在订阅一个BehaviorSubject的时候,它首先将会收到Observable上最近发送一个信号(或者是默认值),接着才会收到Observable上会发送的序列。

Variable:是BehaviorSubject的封装,会保存当前最新值作为状态,重新发送最新或者最近数据给新观察者。虽然Variable是BehaviorSubject的封装,它和BehaviorSubject不同之处在于,不能向Variable发送.Complete和.Error,它会在生命周期结束被释放的时候自动发送.Complete。

Subject的简单使用


PublishSubject

PublishSubjects能够非常容易的处理,在有新事件的时候,订阅者能够接受到通知(在它们订阅之后)。一直到没有订阅者,或者subject有终止,通过发送.completed , .error事件.下面图,最顶部是publish subject,第二行和第三行的是subscribe订阅之后的序列。向上的箭头表示订阅,向下的箭头代表发送事件

第一个订阅者在元素1之前进行订阅,所以,订阅者会接受到事件1和事件2.之后第二个订阅者开始订阅观察者序列,再次发送新消息即事件3,第一个订阅者会接收事件3,第二个订阅者也会接收事件3,但是之前的事件1和事件2并不会接收。这也说明了,PublishSubject只在订阅之后才可以接受最新事件。

example(of: "PublicSubject") {    let disposeBag = DisposeBag()    //1    let subject = PublishSubject<String>()    //2    subject.onNext("Is anyone listening?")    //3    subject.subscribe {            print("第1个订阅者",$0.element ?? $0)    }.addDisposableTo(disposeBag)    //4    subject.on(.next("1"))    subject.onNext("2")    //5    subject.subscribe { event in        print("第2个订阅者", event.element ?? event)    }.addDisposableTo(disposeBag)    //6    subject.onNext("3")    //7    subject.onCompleted()    //8    subject.onNext("5")    //9    subject.subscribe{        print("第3个订阅者", $0.element ?? $0)    }.addDisposableTo(disposeBag)    //10    subject.onNext("?") // 无效}
执行结果和分析:
--- Example of: PublicSubject —
第1个订阅者 1
第1个订阅者 2
第1个订阅者 3
第2个订阅者 3
第1个订阅者 completed
第2个订阅者 completed
第3个订阅者 completed

1: 创建一个公开对象,该对象可以接收信息并发布给订阅者(publisher),类型为string,所以仅仅只接受string类型,一旦被初始化,就准备接收消息
2 :输入一个新的字符串到subject。但是现在并不会有什么内容被打印,因为还没有订阅者(也叫观察者)
3: 创建观察者,但是还是没有任何内容输出?why? why? why? 是因为,我们必须先为subject添加订阅,然后再添加内容,才能得到相应的内容
4: 再此发送消息即添加内容,那么这次可以看到内容了。因为subject已经有订阅者了,所以它将发送text,注意:on(.next(_:) 跟onNext方法是一样的功能,只不过onNext更容易理解,内部包装了一下
5: 添加第二个订阅者
6: 该消息会发送给所有订阅者,这里有两个订阅者,所以都将收到事件
7: 当publishSubject接受.completed或者.error事件,会发送停止事件给所有订阅者,并且不再发送消息即.next事件。但是它将重新发送它的停止事件给将来的订阅者。
8: 为subject发送消息,但是并没有效果,会被忽略掉,因为subject已经终止,即观察者序列已经结束,被终止
9: 再一次为subject进行订阅,并添加到处理包中,仅仅打印完成事件,即终止事件
10: 观察者序列终止,消息发送无效

 BehaviorSubject

 BehaviorSubject工作跟PublicSubject工作相似,除了将重发最新最近的消息给新的订阅者。如下图:

由图可知, 最顶部是BehaviorSubject,BehaviorSubject拥有初始值,第二行和第三行是subscribe订阅之后的序列。向上的箭头表示订阅,向下的箭头代表发送事件。首先第一个订阅者订阅观察者序列,那么获取了BehaviorSubject初始值,再发送消息将依次获取对应消息,当第二个订阅者订阅之后,那么在发送新消息之前,订阅者获取了最近的消息,即绿色球。在发送蓝色球消息之后,获取蓝色球消息。
添加一个帮助函数

//建立一个工具打印相应的信息func print<T: CustomStringConvertible>(label: String, event: Event<T>) {  print(label, event.element ?? event.error ?? event)}

简单使用

//定义一个错误枚举enum MyError: Error {    case anError}example(of: "BehaviorSubject") {    let disposeBag = DisposeBag()    //1    let subject = BehaviorSubject(value: "Initial value")    //2    subject.onNext("x")    //3    subject.subscribe {        print(label: "1)", event: $0)        }.addDisposableTo(disposeBag)    //4    subject.onNext("y")    //5    subject.onError(MyError.anError)    //6    subject.subscribe {        print(label: "2)", event: $0)        }.addDisposableTo(disposeBag)    //7    subject.onNext("z")}
执行结果和分析:
 --- Example of: BehaviorSubject ---
 1) x
 1) y
 1) anError
 2) anError
 
1:创建一个BehaviorSubject,并拥有一个初始值。注意:因为BehaviorSubject经常发送最新最近的元素,所以你不能创建一个BehaviorSubject实例而不提供默认的初始值。如果你不能提供初始值,那么获取就应该使用
PublishSubject
2:发送一个消息x
3:为subject创建一个订阅者,因为之前发送了消息x,所以打印消息x。如果之前不发送消息x,那么没有为subject添加其它的元素,只有初始值,所以会发送初始值给订阅者
4:发送消息y,订阅者将接收消息y
5:为subject添加error,发送错误信息,观察者序列终止
6:为subject创建一个新的订阅者,只为新的订阅者发送上一次的错误信息
7:无效,因为subject已经终止

注意:BehaviorSubject对于一个视图想显示最近的数据是非常有用的。对于个人中心页面的控件,在app获取新数据之前,先显示最近的数据,在获取新数据之后显示新数据。

ReplaySubject

ReplaySubject将在缓冲区(buffer)临时缓存消息,当达到指定的数据大小,subject会发送最新的元素。并且重新发送给新的订阅者,如下图所示:
在第二个订阅者订阅观察者序列之后,前面两次的消息也接收了。

example(of: "replay") {    let disposeBag = DisposeBag()    //1    let subject = ReplaySubject<String>.create(bufferSize: 2)    //2    subject.onNext("1")    subject.onNext("2")    subject.onNext("3")    //3    subject.subscribe {       print(label: "1)", event: $0)    }.addDisposableTo(disposeBag)    //4 第二个订阅    subject.subscribe {       print(label: "2)", event: $0)    }.addDisposableTo(disposeBag)    //5    subject.onNext("4")    //6    subject.onError(MyError.anError)    //7    subject.subscribe {       print(label: "3)", event: $0)    }.addDisposableTo(disposeBag)    //8    subject.onNext("5")}
 执行结果和分析:
 --- Example of: replay ---
 1) 2
 1) 3
 2) 2
 2) 3
 1) 4
 2) 4
 1) anError
 2) anError
 3) 3
 3) 4
 3) anError
 
1:创建一个ReplaySubject,并制定缓冲区大小
2:为subject发送3个新消息
3:开始订阅观察者序列,一旦订阅将获得最新的两个元素,1被忽略了,因为缓冲区大小只能存储两个元素
4:添加第二个订阅者,将获得缓冲区的数据
5:添加新的元素到subject,那么会为之前的两个订阅者发送该消息
6:发送错误消息,终止了当前的观察者序列
7:添加新的订阅者,将获得最新的两个信息,3和4. 因为错误事件,输入终止了观察者序列,但是缓冲内容还在,所以添加新的订阅者,还是会由缓冲的数据向订阅者发送消息,然后由于出错终止,所以会发送错误信息。
8:观察者序列终止,发送消息无效

Variables

正如前面提及的,一个Variables包含了BehaviorSubject,并且存储了当前值作为状态,我们可以通过它的value属性获取值,而且不像前面的几个subject,这里并不使用onNext(_:)添加新元素,而是直接使用value属性进行赋值操作。为了获取包装的BehaviorSubject,我们可以调用asObservable()方法。

Variable独特的地方是,不能发送.error事件,虽然你可以监听.error事件,但是不能添加.error到Variable。Variable将自动发送complete事件,当它即将被释放,所以不需要手动添加.completed事件。

example(of: "Variable") {     let disposeBag = DisposeBag()    //1    var variable = Variable("Initial value")    //2    variable.asObservable().subscribe {      print(label: "1)", event: $0)    }.addDisposableTo(disposeBag)    //3    variable.value = "1"    //4    variable.asObservable().subscribe {      print(label: "2)", event: $0)    }.addDisposableTo(disposeBag)    //5    variable.value = "2"}
执行结果和分析:
 --- Example of: Variable ---
 1) Initial value
 1) 1
 2) 1
 1) 2
 2) 2
 1) completed
 2) completed
 
1:初始化一个Variable实例,类型被自动推测
2:开始订阅观察者序列,首先调用asObservable()获得观察者序列然后开始订阅,立马接收到初始值消息
Initial value
3:发送新消息,订阅者将接受新消息1
4:添加新的订阅者,获得最新的元素值,那么就是消息1
5:新发送新消息,观察者序列将向两个订阅者发送消息,打印2个2,最后自动发送完成事件



0 0