LoginSignup
32
21

More than 5 years have passed since last update.

【Swift】RxSwiftのPlaygroundを読む②

Last updated at Posted at 2016-07-20

RxSwiftのPlaygroundを読んでみるシリーズ今回はSubjectについてです。
(Working_with_Subjects)

Subject

Subjectも川です。
RxSwiftのPlaygroundを読む①で説明した内容と同じことが言えます。

Subjectは加えて、
eventを好きなタイミングで流すことができます。
(subscribeされていなくても。)

複数のsubscribeを区別するため、subscribeメソッドが定義されている
ObservableTypeに以下のメソッドを生やしておきます。

extension ObservableType {

    func subscribe(withID id: String) -> Disposable {
        return subscribe { print("Subscription:", id, "Event:", $0) }
    }
}

PublishSubject

最もシンプルなSubject。
eventを送ったタイミングでsubscribeしていれば、
eventを受け取ることができるSubject。
(過去に送ったeventは受け取れない。)
また、deinit時にcompleteを流さない。

let disposeBag = DisposeBag()
let publishSubject川 = PublishSubject<String>()

publishSubject川
    .subscribe(withID: "1")
    .addDisposableTo(disposeBag)

publishSubject川
    .onNext("🍑1")
publishSubject川
    .onNext("🍑2")

publishSubject川
    .subscribe(withID: "2")
    .addDisposableTo(disposeBag)

publishSubject川
    .onNext("🍑3")
publishSubject川
    .onNext("🍑4")

結果

Subscription: 1 Event: Next(🍑1) // ←まだ2はsubscribeしていない
Subscription: 1 Event: Next(🍑2) // 同上
Subscription: 1 Event: Next(🍑3)
Subscription: 2 Event: Next(🍑3)
Subscription: 1 Event: Next(🍑4)
Subscription: 2 Event: Next(🍑4)

ReplaySubject

subscribe時に指定したbufferSize分の過去のeventを受け取れるSubject。
また、deinit時にcompleteを流さない。

let disposeBag = DisposeBag()
let replaySubject川 = ReplaySubject<String>.create(bufferSize: 1)

replaySubject川
    .subscribe(withID: "1")
    .addDisposableTo(disposeBag)

replaySubject川
    .onNext("🍑1")
replaySubject川
    .onNext("🍑2")

replaySubject川
    .subscribe(withID: "2")
    .addDisposableTo(disposeBag)

replaySubject川
    .onNext("🍑3")
replaySubject川
    .onNext("🍑4")

結果

Subscription: 1 Event: Next(🍑1)
Subscription: 1 Event: Next(🍑2)
Subscription: 2 Event: Next(🍑2) // ←1つ過去のeventを受け取っている
Subscription: 1 Event: Next(🍑3)
Subscription: 2 Event: Next(🍑3)
Subscription: 1 Event: Next(🍑4)
Subscription: 2 Event: Next(🍑4)

BehaviorSubject

subscribe時に、一つ過去のevent(最初にsubscribeする場合は初期値)を受け取れるSubject。
ReplaySubjectでbufferSizeを1にしたときと同様の挙動(初期値を除いて)。
また、deinit時にcompleteを流さない。

let disposeBag = DisposeBag()
let behaviorSubject川 = BehaviorSubject<String>(value: "🍑0")

behaviorSubject川
    .subscribe(withID: "1")
    .addDisposableTo(disposeBag)

behaviorSubject川
    .onNext("🍑1")
behaviorSubject川
    .onNext("🍑2")

behaviorSubject川
    .subscribe(withID: "2")
    .addDisposableTo(disposeBag)

behaviorSubject川
    .onNext("🍑3")
behaviorSubject川
    .onNext("🍑4")

結果

Subscription: 1 Event: Next(🍑0) // ←初期値
Subscription: 1 Event: Next(🍑1)
Subscription: 1 Event: Next(🍑2)
Subscription: 2 Event: Next(🍑2) // ←1つ過去のeventを受け取っている
Subscription: 1 Event: Next(🍑3)
Subscription: 2 Event: Next(🍑3)
Subscription: 1 Event: Next(🍑4)
Subscription: 2 Event: Next(🍑4)

Variable

BehaviorSubject同様、1つ過去のeventを受け取れるSubject。
相違点は
・valueプロパティに直近のnextの値が保存されており、新たにnextイベントを流す場合はvalueプロパティを変更する。
・errorが流れない。
・deinit時にcompleteが流れる。

let disposeBag = DisposeBag()
let variable川 = Variable("🍑0")

variable川.asObservable()
    .subscribe(withID: "1")
    .addDisposableTo(disposeBag)

variable川.value = "🍑1"
variable川.value = "🍑2"

variable川.asObservable()
    .subscribe(withID: "2")
    .addDisposableTo(disposeBag)

variable川.value = "🍑3"
variable川.value = "🍑4"

結果

Subscription: 1 Event: Next(🍑0)
Subscription: 1 Event: Next(🍑1)
Subscription: 1 Event: Next(🍑2)
Subscription: 2 Event: Next(🍑2)
Subscription: 1 Event: Next(🍑3)
Subscription: 2 Event: Next(🍑3)
Subscription: 1 Event: Next(🍑4)
Subscription: 2 Event: Next(🍑4)

おわりに

うまく言語化できないあたり、まだまだよくわかっていないようです。
些細なことでもいいので、何かありましたらコメントお願いします。

次回はいくつかのObservableを束ねる処理についてです。

参考

32
21
1

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
32
21