RxSwift(六) - Subjects、 Variables

Subjects

创建 Observable 序列之后, 要预先将要发出的数据准备好, 等到有人订阅时, 再将数据通过 Event 发出去.

我们希望 Observable 序列能在运行时动态的 获得 或者说 产生 一个新数据, 再通过 Event 发送出去. 比如: 订阅一个输入框的输入内容, 当用户每输入一个字后, 这个输入框关联的 Observable 就会发出一个带有输入内容的 Event, 通知给所有的订阅者. 这个就可以使用 Subjects 来实现.

Subjects 基本介绍

(1) Subjects 它是订阅者, 也是 Obervable :

  • 它是订阅者, 因为它能够动态的接收新的值
  • 它是一个 Observable, 是因为当 Subjects 有了新的值之后, 就会通过 Event 将新值发出给他的所有订阅者.

(2) 一共有四种 Subjects, 分别是 PublishSubjectBehaviorSubjectReplaySubjectVariable(已废弃)BehaviorRelay(Variable替代品).

  • 它们都是 Observable, 它们的订阅者都能收到它们发出的 Event
  • 直到 Subject 发出 .complete 或者 .errorEvent 之后, 该 Subject 才会终结, 不再发出 .next 事件.
  • 对于那些在 Subject 终结后再订阅的订阅者, 也能收到一条 .complete 或者 .errorEvent, 告诉这个新订阅者, 该 Subject 已经终结
  • 它们的区别在于 : 当一个新的订阅者刚订阅它的时候,能不能收到 Subject 以前发出的旧 Event, 如果能,又可以收到多少个 Event.

(3) Subject 的常用方法

  • onNext() : on(.next):的简写, 该方法相当于 subject 接收到一个 .next 事件.
  • onError() : on(.error): 的简写, 该方法相当于 subject 接收到一个 .error 事件.
  • onCompleted() : on(.completed): 的简写, 该方法相当于 subjet 接收到一个 .completed 事件
PublishSubject

(1) 基本介绍

  • PublishSubject 是最普通的 Subjet, 它不需要初始值就能创建.
  • PublishSubject 的订阅者从开始订阅的时间点起,可以收到订阅 Subject 发出的新的 Event, 而不会收到他们在订阅前已发出的 Event.
PublishSubject.png

(2)案例

override func viewDidLoad() {
        super.viewDidLoad()
        let disposeBag = DisposeBag()
        //创建一个PublishSubject
        let subject = PublishSubject<String>()
        subject.onNext("11") //此时没有订阅者,不会输出
        
        //首次订阅
        subject.subscribe(onNext: { str in
            print("第一次订阅: ", str)
        }, onCompleted: {
            print("第一次订阅 : onCompleted")
        }).disposed(by: disposeBag)
        //有订阅者,会输出
        subject.onNext("22")
        
        subject.subscribe(onNext: { (str) in
            print("第二次订阅: ", str)
        }, onCompleted: {
            print("第二次订阅 : onCompleted")
        }).disposed(by: disposeBag)
        subject.onNext("33")//两个订阅者,输出两遍
        subject.onCompleted()//结束两个订阅者,打印两遍
        subject.onNext("44")//再次发送event,不会打印
        //再有新的订阅者,会收到onCompleted消息,通知新的订阅者,该Subject已经终结
        subject.subscribe(onNext: { (str) in
            print("第三次订阅: ", str)
        }, onCompleted: {
            print("第三次订阅 : onCompleted")
        }).disposed(by: disposeBag)
}

//输出结果 
第一次订阅:  22
第一次订阅:  33
第二次订阅:  33
第一次订阅 : onCompleted
第二次订阅 : onCompleted
第三次订阅 : onCompleted
BehaviorSubject

(1) 基本介绍

  • BehaviorSubject 需要通过一个默认初始值来创建
  • 当一个订阅者来订阅它的时候, 这个订阅者会立即收到 BehaviorSubject 上一个发出的 event, 之后就是正常流程
    BehaviorSubject.png

(2) 使用示例

override func viewDidLoad() {
        super.viewDidLoad()
        let disposeBag = DisposeBag()
        let subject = BehaviorSubject(value: "111")
        //第一次订阅subject(先发出上一个event)
        subject.subscribe { (event) in
            print("第一次订阅: ", event)
        }.disposed(by: disposeBag)
        //发送next事件
        subject.onNext("222")
        subject.onError(NSError(domain: "local", code: 0, userInfo: nil))
        //重复结束event,输出error
        subject.subscribe { (event) in
            print("第二次订阅: ",event)
        }.disposed(by: disposeBag)
    }
    
//输出结果
第一次订阅:  next(111)
第一次订阅:  next(222)
第一次订阅:  error(Error Domain=local Code=0 "(null)")
第二次订阅:  error(Error Domain=local Code=0 "(null)")
ReplaySubject

(1) 基本介绍

  • ReplaySubject 在创建的时候需要设置一个 bufferSize, 表示它发送过的 event 缓存个数. 比如 : 一个 ReplaySubjectbufferSize 设置为 2, 它发出了三个 .nextevent, 那么这个 subscriber 就会立即收到前面缓存的两个 .nextevent

(2) 时序图

  • ReplaySubjectbufferSize2
  • 下面两条订阅, 订阅时间点不同. ReplaySubject 的订阅者一开始就能受到 ReplaySubject 之前发出的两个 Event(如果有的话).
    ReplaySubject.png

    (3)案例
override func viewDidLoad() {
        super.viewDidLoad()
        let disposeBag = DisposeBag()
        let subject = ReplaySubject<String>.create(bufferSize: 2);
        //连续发出三个event
        subject.onNext("1")
        subject.onNext("2")
        subject.onNext("3")
        //第一次订阅
        subject.subscribe { (event) in
            print("第一次订阅", event)
        }.disposed(by: disposeBag)
        
        subject.onNext("4")
        subject.subscribe { (event) in
            print("第二次订阅", event)
        }
        
        subject.onCompleted();
        subject.subscribe { (event) in
            print("第三次订阅", event)
        }.disposed(by: disposeBag)
        
    }
    
//输出结果
第一次订阅 next(2)
第一次订阅 next(3)
第一次订阅 next(4)
第二次订阅 next(3)
第二次订阅 next(4)
第一次订阅 completed
第二次订阅 completed
第三次订阅 next(3)
第三次订阅 next(4)
第三次订阅 completed
BehaviorRelay

(1) 基本介绍

  • BehaviorRelay 是作为 Variable 的替代者出现的. 它的本质其实也是对 BehaviorRelay 的封装, 所以它也必须要通过一个默认的初始值进行创建
  • BehaviorReplay 具有 BehaviorSubject 的功能, 能够向它的订阅者发出上一个 event 以及之后新创建的 event
  • BehaviorSubject 不同的是,不需要也不能手动给 BehaviorReply 发送 completed 或者 error 事件来结束它(BehaviorRelay 会在销毁时自动发送 .complete 的 event)。
  • BehaviorReplay 有一个 value 属性, 我们通过这个属性可以获取最新值. 而通过它的 accept() 方法可以对值进行修改.

(2) 案例

override func viewDidLoad() {
        super.viewDidLoad()
        let disposeBag = DisposeBag()
        let subject = BehaviorRelay<String>(value: "111");
        // 修改value值
        subject.accept("222");
        //第一次订阅
        subject.subscribe { (event) in
            print("第一次订阅: ", event)
        }.disposed(by: disposeBag)
        
        //修改value值
        subject.accept("333")
        subject.subscribe { (event) in
            print("第二次订阅 :", event)
        }.disposed(by: disposeBag)

        subject.accept("444")
    }
//输出结果
第一次订阅:  next(222)
第一次订阅:  next(333)
第二次订阅 : next(333)
第一次订阅:  next(444)
第二次订阅 : next(444)
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,530评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,403评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,120评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,770评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,758评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,649评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,021评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,675评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,931评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,751评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,410评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,004评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,969评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,042评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,493评论 2 343

推荐阅读更多精彩内容