LoginSignup
2

More than 3 years have passed since last update.

RxSwiftで、2回に1回イベントを流すObservableを作ってみた

Posted at

2番煎じかもしれませんが、ざっと探したら見つからなかったので。
他にあれば教えて下さい(笑い

実装方針

  • scanを使って、Bool値をtrue -> false -> true -> falseのように都度切り替えて流す
  • そのBool値をつかって、filterする
let intSubject = PublishSubject<Int>()
let subject =
    intSubject
        .scan((true, 0)) { (output, update) -> (Bool, Int) in
            //Bool値を反転して返してあげると、ストリームの度に値が変わることになる
            //初期値はtrueを反転するのでfalseから始まる。結果として奇数回を飛ばすことになる
            return (!output.0, update)
        }
        .compactMap { (flag, value) -> Int? in
            flag ? value : nil
        }
subject.bind { print($0) }

intSubject.onNext(1)
intSubject.onNext(2)
intSubject.onNext(3)
intSubject.onNext(4)
intSubject.onNext(5)
intSubject.onNext(6)
//結果
2
4
6

compactMap使ってますので、流す型がInt? だとおかしくなりますね。素直に filterとmapで書いたほうが良さそうです。あとはscanの初期値として渡している 0 も型を特定する以上の役割がないので要らないかなぁ

汎用化してみました

extension をつかって、Observableの関数化してみます。

extension Observable {
    //isEvenは偶数回だけイベントを流すか、奇数回だけにするかを決定するフラグ
    func onceInTwice(isEven: Bool) -> Observable<Element> {
        let initial: (Bool,[Element]) = (isEven, [])
        return
            scan(initial) { (output, update) -> (Bool, [Element]) in
                return (!output.0, [update])
            }
            .filter { (flag, _) in return flag }
            .map { (_, value)  in return value.first! }
    }
}

let input = PublishSubject<String?>()
let onceInTwice = input.onceInTwice(isEven: false)

onceInTwice.bind { print($0) }

input.onNext("1回目")
input.onNext("2回目")
input.onNext(nil)
input.onNext("4回目")
input.onNext("5回目")
input.onNext("6回目")

//結果
Optional("1回目")
nil
Optional("5回目")

期待どおりに動いてくれてそうです〜。

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
2