天天看点

RxSwift(3.4.1)- Subjects什么是SubjectSubject的类型Subject的简单使用

什么是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订阅之后的序列。向上的箭头表示订阅,向下的箭头代表发送事件

RxSwift(3.4.1)- Subjects什么是SubjectSubject的类型Subject的简单使用

第一个订阅者在元素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工作相似,除了将重发最新最近的消息给新的订阅者。如下图:

RxSwift(3.4.1)- Subjects什么是SubjectSubject的类型Subject的简单使用

由图可知, 最顶部是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会发送最新的元素。并且重新发送给新的订阅者,如下图所示: 在第二个订阅者订阅观察者序列之后,前面两次的消息也接收了。

RxSwift(3.4.1)- Subjects什么是SubjectSubject的类型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,最后自动发送完成事件