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