1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

RxSwiftの.share()オペレーターの挙動についてまとめた

Posted at

.share()について

  • ColdからHotに変換するオペレーター
  • Observableを複数のサブスクライバーで共有することができる
public func share(replay: Int = 0, scope: SubjectLifetimeScope = .whileConnected) -> Observable<Element> {
  switch scope {
  case .forever:
    switch replay {
    case 0: return self.multicast(PublishSubject()).refCount()
    default: return self.multicast(ReplaySubject.create(bufferSize: replay)).refCount()
    }
  case .whileConnected:
    switch replay {
    case 0: return ShareWhileConnected(source: self.asObservable())
    case 1: return ShareReplay1WhileConnected(source: self.asObservable())
    default: return self.multicast(makeSubject: { ReplaySubject.create(bufferSize: replay) }).refCount()
    }
  }
}
  • replay: リプレイするイベントの最大キャッシュ数
    • 0の場合はリプレイされない
    • 共通のサブスクライバーがいくつあって、何番目のサブスクライバーまでイベントを流すかによって値が変わる
  • scope: 共有をいつまで続けるかのオプション
    • .forever : 一度サブスクライブすると永久的にアクティブになり、新たにサブスクライブされた場合もストリームが共有される
      • 一度取得した値を全ての画面やコンポーネントで使用する場合に使う
      • アプリの設定情報など
    • .whileConnected : アクティブなサブスクライバーが存在する間のみ有効
      • disposeされると全て解放される

.share()使用しないでサブスクライブした場合

let subject = PublishSubject<Int>()
let observable = subject
  .debug("observable")

observable
  .bind(to: Binder(self) { _, value in
    print("サブスクライバー1: \(value)")
  })
  .disposed(by: bag)

// 1回目のイベントを発行
subject.onNext(1)

observable
  .bind(to: Binder(self) { _, value in
    print("サブスクライバー2: \(value)")
  })
  .disposed(by: bag)

// 2回目のイベントを発行
subject.onNext(2)

// --- 実行結果 --- 
// observable -> subscribed
// observable -> Event next(1)
// サブスクライバー1: 1
// observable -> subscribed
// observable -> Event next(2)
// サブスクライバー1: 2
// observable -> Event next(2)
// サブスクライバー2: 2

Observableが2回サブスクライブされておりストリームが分離している
また2回目のonNextはサブスクライバー1には流れていない

.share()を使用してサブスクライブした場合

let subject = PublishSubject<Int>()
let observable = subject
  .debug("observable")
	.share()

observable
  .bind(to: Binder(self) { _, value in
    print("サブスクライバー1: \(value)")
  })
  .disposed(by: bag)

// 1回目のイベントを発行
subject.onNext(1)

observable
  .bind(to: Binder(self) { _, value in
    print("サブスクライバー2: \(value)")
  })
  .disposed(by: bag)

// 2回目のイベントを発行
subject.onNext(2)

// --- 実行結果 --- 
// observable -> subscribed
// observable -> Event next(1)
// サブスクライバー1: 1
// observable -> Event next(2)
// サブスクライバー1: 2
// サブスクライバー2: 2

サブスクライバー2はサブスクライバー1と共通のObservableなのでストリームは分離していない
しかし、サブスクライバー2は1回目のonNextの後でサブスクライブしているので、1回目のonNextの値が流れてこない

.share(replay: 1)を使用した場合

let subject = PublishSubject<Int>()
let observable = subject
  .debug("observable")
	.share(replay: 1)

observable
  .bind(to: Binder(self) { _, value in
    print("サブスクライバー1: \(value)")
  })
  .disposed(by: bag)

// 1回目のイベントを発行
subject.onNext(1)

observable
  .bind(to: Binder(self) { _, value in
    print("サブスクライバー2: \(value)")
  })
  .disposed(by: bag)

// 2回目のイベントを発行
subject.onNext(2)

// --- 実行結果 --- 
// observable -> subscribed
// observable -> Event next(1)
// サブスクライバー1: 1
// サブスクライバー2: 1
// observable -> Event next(2)
// サブスクライバー1: 2
// サブスクライバー2: 2

share(replay: 1)を使用するとストリームのイベントがreplay: n分キャッシュされて、後続のサブスクライバーがキャッシュされたイベントを受け取ることができる
そのため、サブスクライバー2は1回目のonNextの値を受け取ることができ、1つのストリームで同じ値を受け取ることができる

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?