(追記) : こちらで詳しく書き直しています。
続・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)
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で絞ったストリームと、neverをconcatで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)
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)
となります。