iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 6
0
Mobile Development

RxSwift / 30天探索之旅系列 第 6

第 6 天 - Subject (下)

昨天稍微介紹Subject的用途,今天進一步來介紹他的兄弟姐妹,共有6種,看起來很多,但仔細看就會發現差不多那幾個字組合而已,下面聽我娓娓道來,Relay因為篇幅關係,我們拿到明天再補充

  • PublishSubject
  • BehaviorSubject
  • ReplaySubject
  • AsyncSubject(這很少用到,就不提了)
  • PublishRelay
  • BehaviorRelay

PublishSubject

昨天有稍微提到,PublishSubject定義『開始是空的,只會發送新的元素給訂閱者』,畫成圖會像下面這樣,訂閱者在數字1之後訂閱,只能等到再次發送數字2,才可以收到。
https://ithelp.ithome.com.tw/upload/images/20200920/20115751BLywDtkXEP.png
寫成程式碼如下,大家可以執行看看

let subject = PublishSubject<String>()

subject.onNext("1")
// 1, 2
subject
    .debug("A")
    .subscribe()
    .disposed(by: disposeBag)

subject.onNext("2")

subject.onNext("3")

subject
    .debug("B")
    .subscribe()
    .disposed(by: disposeBag)
// 3
subject.onError(NSError(domain: "Test", code: -1, userInfo: nil))

執行結果如下

A -> subscribed
A -> Event next(2)
A -> Event next(3)
B -> subscribed
A -> Event error(Error Domain=Test Code=-1 "(null)")
Unhandled error happened: Error Domain=Test Code=-1 "(null)"
A -> isDisposed
B -> Event error(Error Domain=Test Code=-1 "(null)")
Unhandled error happened: Error Domain=Test Code=-1 "(null)"
B -> isDisposed
  1. 我這邊不在用.subscribe(onNext, onError),而是改用.debug().debug()顧名思義是在除錯時候使用,他可以把訂閱的開始到結束都印出來,帶入的String代表他的名稱,實際使用上可以使用emoji,視覺上圖片比文字能更快速辨認(但it邦好像不能使用emoji...,這裡替換成數字跟英文字母)
  2. 因為我只是想列印,並沒有要處理任何事件,但如果Obsevable沒有訂閱者的話,它是不會發送任何元素的,所以這邊我們就寫.subscribe()就好。
  3. 因為B比較晚訂閱,所以他收不到前面的元素,又因為收到.error而disposed。

BehaviorSubject

如果你要一訂閱就拿到上一次的值,可以使用BehaviorSubject,它定義是這樣的『開始是預設值,發送目前的最後一個值給訂閱者』,也就是說你不管什麼時候訂閱,都會有元素可以收到(至少有預設值)。
https://ithelp.ithome.com.tw/upload/images/20200920/20115751FkVQZd4dgL.png
寫成程式碼如下,在建構BehaviorSubject需要再多給一個預設值

let subject = BehaviorSubject<String>(value: "1")

subject
    .debug("A")
    .subscribe()
    .disposed(by: disposeBag)

subject.onNext("2")
// 2
print("Subject value: \(try! subject.value())")

subject.onNext("3")

subject.onError(NSError(domain: "Test", code: -1, userInfo: nil))

subject
    .debug("B")
    .subscribe()
    .disposed(by: disposeBag)
// 3
print("Subject value: \(try! subject.value())")

執行結果如下

A -> subscribed
A -> Event next(1)
A -> Event next(2)
Subject value: 2
A -> Event next(3)
A -> Event error(Error Domain=Test Code=-1 "(null)")
Unhandled error happened: Error Domain=Test Code=-1 "(null)"
A -> isDisposed
B -> subscribed
B -> Event error(Error Domain=Test Code=-1 "(null)")
Unhandled error happened: Error Domain=Test Code=-1 "(null)"
B -> isDisposed
Fatal error: 'try!' expression unexpectedly raised an error: Error
  1. Behavior多了.value()這個func可以使用,他可以取的目前最新的元素,考慮到有Observable可能是.error或是disposed,所以會throws RxError,這邊使用try!單純只是作為範例展示。
  2. B在.error 訂閱,你收到的不是.next(3),因為現在最後一個元素是.error哦!
  3. Subject value:在第一次會收到.next(2),第二次因為收到.error而throws錯誤

ReplaySubject

如果你要一訂閱就拿到上n次的值,那你要選擇ReplaySubject,它定義是『開始時給訂一個暫存大小(buffer size),發送時會將最後的n個元素存進暫存,並將暫存的元素發給訂閱者』,下圖就是以bufferSize = 2 的情況。
https://ithelp.ithome.com.tw/upload/images/20200920/20115751l4IqnkzasC.png
寫成程式碼如下,建構時需要給定bufferSize

let subject = ReplaySubject<String>.create(bufferSize: 2)

subject.onNext("1")

subject.onNext("2")

subject.onNext("3")
// 1
subject
    .debug("A")
    .subscribe()
    .disposed(by: disposeBag)

subject.onNext("4")

subject.onNext("5")

subject.onError(NSError(domain: "Test", code: -1, userInfo: nil))
// 2
subject
    .debug("B")
    .subscribe()
    .disposed(by: disposeBag)

執行結果如下

A -> subscribed
A -> Event next(2)
A -> Event next(3)
A -> Event next(4)
A -> Event next(5)
A -> Event error(Error Domain=Test Code=-1 "(null)")
Unhandled error happened: Error Domain=Test Code=-1 "(null)"
A -> isDisposed
B -> subscribed
B -> Event next(4)
B -> Event next(5)
B -> Event error(Error Domain=Test Code=-1 "(null)")
Unhandled error happened: Error Domain=Test Code=-1 "(null)"
B -> isDisposed
  1. A訂閱的時機點是在3之後,這時buffer存了2和3,所以他會從2開始接收。
  2. B訂閱時間點,他除了接收到buffer中元素,如果Observable已經結束,還會在收到.error(或 .completed),所以這裡才是接收到4、5和.error,這是跟前面兩種Subject比較不同的。

本來昨天說要探討一下Subject的使用時機,但發現講完前三個Subject類型,篇幅好像就有點多了?留在明天或後天講好了!就這樣,掰掰


上一篇
第 5 天 - Subject (上)
下一篇
第 7 天 - Relay
系列文
RxSwift / 30天探索之旅30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言