share(replay:scope:) 作用:
解決有多個(gè)訂閱者
的情況下琳轿,避免
事件轉(zhuǎn)換操作符(比如:map判沟、flatMap耿芹、flatMapLatest等等
)被多次執(zhí)行的問題
#普通的可觀察序列
let seq = PublishSubject<Int>()
let ob = seq.map { (i) -> Int in
print("map 被調(diào)用 :---\(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)
/// 打印結(jié)果:
/// map 被調(diào)用 :---1
/// --第一次訂閱--2
/// map 被調(diào)用 :---1
/// --第二次訂閱--2
#帶share
let seq = PublishSubject<Int>()
let ob = seq.map { (i) -> Int in
print("map 被調(diào)用 :---\(i)")
return i * 2
}
/// replay:緩存的事件個(gè)數(shù)
/// scope:subject是否獨(dú)立(使用說明請(qǐng)看下方)
.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)
/// 打印結(jié)果:
/// map 被調(diào)用 :---1
/// --第一次訂閱--2
/// --第二次訂閱--2
總結(jié)
:
從上面例子可以知道:
發(fā)送一次onNext事件,就對(duì)應(yīng)一個(gè)Observable挪哄,而所有的觀察者都只對(duì)應(yīng)這個(gè)Observable吧秕,Observable共享給所有的觀察者
share(replay:scope:)
操作符使得觀察者共享Observable
,并且緩存最新的n個(gè)元素
迹炼,將這些元素直接發(fā)送給新的觀察者
看了上面的兩個(gè)例子砸彬,貌似已經(jīng)懂得share操作符的基本使用,嘻嘻嘻嘻
請(qǐng)繼續(xù)看下面的例子
# 代碼一:沒有使用share
let net = Observable<String>.create { (ob) -> Disposable in
print("我開始網(wǎng)絡(luò)請(qǐng)求了")
ob.onNext("請(qǐng)求結(jié)果")
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)
/// 打印結(jié)果:
/// 我開始網(wǎng)絡(luò)請(qǐng)求了
/// 第一次訂閱:請(qǐng)求結(jié)果 <NSThread: 0x600002ce0a40>{number = 1, name = main}
/// 銷毀了
/// 我開始網(wǎng)絡(luò)請(qǐng)求了
/// 第二次訂閱:請(qǐng)求結(jié)果 <NSThread: 0x600002ce0a40>{number = 1, name = main}
/// 銷毀了
# 代碼二:share(replay: 0, scope: .whileConnected)
let net = Observable<String>.create { (ob) -> Disposable in
print("我開始網(wǎng)絡(luò)請(qǐng)求了")
ob.onNext("請(qǐng)求結(jié)果")
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)
/// 打印結(jié)果:
/// 我開始網(wǎng)絡(luò)請(qǐng)求了
/// 第一次訂閱:請(qǐng)求結(jié)果 <NSThread: 0x600001b1c900>{number = 1, name = main}
/// 銷毀了
/// 我開始網(wǎng)絡(luò)請(qǐng)求了
/// 第二次訂閱:請(qǐng)求結(jié)果 <NSThread: 0x600001b1c900>{number = 1, name = main}
/// 銷毀了
首先通過上面兩端代碼的打印結(jié)果斯入,發(fā)現(xiàn)share貌似也不起什么作用砂碉,其實(shí)不然。講這個(gè)之前刻两,請(qǐng)先看RxSwift中對(duì)share方法中對(duì)scope參數(shù)的注釋
* `.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
是一個(gè)枚舉值增蹭,包括whileConnected、forever
官方文檔注釋的大概意思是:
whileConnected:每個(gè)connection 都有單獨(dú)的一個(gè)Subject存儲(chǔ)事件Event
forever:用一個(gè)Subject存儲(chǔ)所有的connections的事件Event
為了理解這個(gè)磅摹,我們將“代碼二”中的.whileConnected 修改為 .forever
看看結(jié)果有什么不一樣的
#代碼三
let net = Observable<String>.create { (ob) -> Disposable in
print("我開始網(wǎng)絡(luò)請(qǐng)求了")
ob.onNext("請(qǐng)求結(jié)果")
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)
/// 打印結(jié)果:
/// 我開始網(wǎng)絡(luò)請(qǐng)求了
/// 第一次訂閱:請(qǐng)求結(jié)果 <NSThread: 0x600003390480>{number = 1, name = main}
/// 銷毀了
發(fā)現(xiàn)打印結(jié)果滋迈,少了訂閱2霎奢。這是為什么了?
根據(jù)注釋饼灿,.forever 是使用一個(gè)Subject存儲(chǔ)所有的連接的Event幕侠,
在第一次訂閱的時(shí)候,觸發(fā)Observable的構(gòu)建函數(shù)碍彭,但是在發(fā)送事件完之后就發(fā)送了complete晤硕,既然已經(jīng)發(fā)送了complete那么代表存儲(chǔ)的Subject已經(jīng)結(jié)束了,所以第二次訂閱并沒有打印
PS: 這種情況如果想要實(shí)現(xiàn)多次訂閱庇忌,然后只執(zhí)行一次網(wǎng)絡(luò)請(qǐng)求的窗骑,可以參考這個(gè)文章的解決方案:使用功能操作符
. publish
項(xiàng)目使用
項(xiàng)目比較常用的可能就是封裝網(wǎng)絡(luò)請(qǐng)求的Observable
中,在Observable中添加share(replay:scope:)操作符漆枚,目的是為了在多個(gè)位置訂閱创译,避免發(fā)一次的Event,而重復(fù)多個(gè)請(qǐng)求