LoginSignup
10

More than 5 years have passed since last update.

`take`してもcompletedさせない

Last updated at Posted at 2016-12-22

(追記) : こちらで詳しく書き直しています。
続・takeしてもcompletedにさせない

ちょっとした小ネタです。(カレンダー埋めさせてください...!)

takeを使ってイベント送信を絞る

takeを使って、イベント送信を指定した回数だけ絞ることができるのですが、
takeで指定した回数分イベントが流れると、completedが流れます

let subject = PublishSubject<Int>()

subject.take(1)
    .subscribe { print($0) }
    .addDisposableTo(disposeBag)

subject.onNext(1)
subject.onNext(2)
subject.onNext(3)
output
next(1)
completed

ちょっとした問題

ただ、場合によっては、 completed が流れることで他のストリームに影響がでてしまうこともあります。

let subject = PublishSubject<Int>()

subject.take(1)
    .bindTo(otherSubject)
    .addDisposableTo(disposeBag)
// subjectでイベントが1回送信されたあと、`completed`してしまうことで
// bindした別のストリームに影響がでることもある。

なので、takeで絞りつつも、completedが流れないようにしてみます。

concat(merge)neverを活用する

takeで絞ったストリームと、neverconcatで1つのストリームに合成します。
そうすることで、takeで絞ったイベントが実行された後は、neverがあることでcompletedせずにすみます

Observable.of(subject.take(1), Observable.never())
    .concat()
    .subscribe { print($0) }
    .addDisposableTo(disposeBag)

subject.onNext(1)
subject.onNext(2)
subject.onNext(3)
output
next(1)
// completedにならない!!

余談(別解)

take(1)の代わりに、singleを使っても同じことができます。
ただ、singleの場合は、2回目以降イベントが送信されるとerrorが流れてくるので、それを握りつぶしてあげる必要があります。

Observable.of(subject.single().catchError { _ in Observable.never() }, Observable.never())
    .concat()
    .subscribe { print($0) }
    .addDisposableTo(disposeBag)

ちょっとした例

以前にこちらの記事を書いたのですが、この例だと

Observable.of(rx.viewWillAppear.take(1), Observable.never())
    .concat()
    .subscribe(onNext: {
        print("viewWillAppearが呼ばれた!")
    })
    .addDisposableTo(disposeBag)

となります。

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
10