RxSwift_操作符_share(replay:scope:)

share(replay:scope:) 作用:
解决有多个订阅者的情况下,避免事件转换操作符(比如:map、flatMap、flatMapLatest等等)被多次执行的问题

#普通的可观察序列
let seq = PublishSubject<Int>()
let ob = seq.map { (i) -> Int in
    print("map 被调用 :---\(i)")
    return i * 2
}

let _ = ob.subscribe(onNext: { (num) in
    print("--第一次订阅--\(num)")
}, onError: nil, onCompleted: nil, onDisposed: nil)


let _ = ob.subscribe(onNext: { (num) in
    print("--第二次订阅--\(num)")
}, onError: nil, onCompleted: nil, onDisposed: nil)

seq.onNext(1)

/// 打印结果:
/// map 被调用 :---1
/// --第一次订阅--2
/// map 被调用 :---1
/// --第二次订阅--2
#带share 

let seq = PublishSubject<Int>()
let ob = seq.map { (i) -> Int in
    print("map 被调用 :---\(i)")
    return i * 2
}
/// replay:缓存的事件个数
/// scope:subject是否独立(使用说明请看下方)
.share(replay: 0, scope: .forever)

let _ = ob.subscribe(onNext: { (num) in
    print("--第一次订阅--\(num)")
}, onError: nil, onCompleted: nil, onDisposed: nil)


let _ = ob.subscribe(onNext: { (num) in
    print("--第二次订阅--\(num)")
}, onError: nil, onCompleted: nil, onDisposed: nil)

seq.onNext(1)

/// 打印结果:
/// map 被调用 :---1
/// --第一次订阅--2
/// --第二次订阅--2

总结
从上面例子可以知道:
发送一次onNext事件,就对应一个Observable,而所有的观察者都只对应这个Observable,Observable共享给所有的观察者

share(replay:scope:) 操作符使得观察者共享Observable,并且缓存最新的n个元素,将这些元素直接发送给新的观察者

看了上面的两个例子,貌似已经懂得share操作符的基本使用,嘻嘻嘻嘻
请继续看下面的例子

# 代码一:没有使用share

let net = Observable<String>.create { (ob) -> Disposable in
    print("我开始网络请求了")
    ob.onNext("请求结果")
    ob.onCompleted()
    return Disposables.create {
        print("销毁了")
    }
}

net.subscribe(onNext:{
    print("第一次订阅:\($0)",Thread.current)
}).disposed(by: bag)

net.subscribe(onNext:{
  print("第二次订阅:\($0)",Thread.current)
}).disposed(by: bag)


/// 打印结果:
/// 我开始网络请求了
/// 第一次订阅:请求结果 <NSThread: 0x600002ce0a40>{number = 1, name = main}
/// 销毁了
/// 我开始网络请求了
/// 第二次订阅:请求结果 <NSThread: 0x600002ce0a40>{number = 1, name = main}
/// 销毁了
# 代码二:share(replay: 0, scope: .whileConnected)

let net = Observable<String>.create { (ob) -> Disposable in
    print("我开始网络请求了")
    ob.onNext("请求结果")
    ob.onCompleted()
    return Disposables.create {
        print("销毁了")
    }
}.share(replay: 0, scope: .whileConnected)


net.subscribe(onNext:{
    print("第一次订阅:\($0)",Thread.current)
}).disposed(by: bag)

net.subscribe(onNext:{
  print("第二次订阅:\($0)",Thread.current)
}).disposed(by: bag)

/// 打印结果:
/// 我开始网络请求了
/// 第一次订阅:请求结果 <NSThread: 0x600001b1c900>{number = 1, name = main}
/// 销毁了
/// 我开始网络请求了
/// 第二次订阅:请求结果 <NSThread: 0x600001b1c900>{number = 1, name = main}
/// 销毁了

首先通过上面两端代码的打印结果,发现share貌似也不起什么作用,其实不然。讲这个之前,请先看RxSwift中对share方法中对scope参数的注释

* `.whileConnected`
// Each connection will have it's own subject instance to store replay events.
// Connections will be isolated from each another.
// source.multicast(makeSubject: { Replay.create(bufferSize: replay) }).refCount()

* `.forever`
// One subject will store replay events for all connections to source.
// Connections won't be isolated from each another.
// source.multicast(Replay.create(bufferSize: replay)).refCount()

scope是一个枚举值,包括whileConnected、forever
官方文档注释的大概意思是:
whileConnected:每个connection 都有单独的一个Subject存储事件Event
forever:用一个Subject存储所有的connections的事件Event

为了理解这个,我们将“代码二”中的.whileConnected 修改为 .forever
看看结果有什么不一样的

#代码三

let net = Observable<String>.create { (ob) -> Disposable in
    print("我开始网络请求了")
    ob.onNext("请求结果")
    ob.onCompleted()
    return Disposables.create {
        print("销毁了")
    }
}.share(replay: 0, scope: .forever)


net.subscribe(onNext:{
    print("第一次订阅:\($0)",Thread.current)
})
.disposed(by: bag)

net.subscribe(onNext:{
  print("第二次订阅:\($0)",Thread.current)
}).disposed(by: bag)

/// 打印结果:
/// 我开始网络请求了
/// 第一次订阅:请求结果 <NSThread: 0x600003390480>{number = 1, name = main}
/// 销毁了

发现打印结果,少了订阅2。这是为什么了?
根据注释,.forever 是使用一个Subject存储所有的连接的Event,
在第一次订阅的时候,触发Observable的构建函数,但是在发送事件完之后就发送了complete,既然已经发送了complete那么代表存储的Subject已经结束了,所以第二次订阅并没有打印

PS: 这种情况如果想要实现多次订阅,然后只执行一次网络请求的,可以参考这个文章的解决方案:使用功能操作符. publish

项目使用

项目比较常用的可能就是封装网络请求的Observable中,在Observable中添加share(replay:scope:)操作符,目的是为了在多个位置订阅,避免发一次的Event,而重复多个请求

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

推荐阅读更多精彩内容