Help us understand the problem. What is going on with this article?

ズンドコキヨシ with Combine

TL; DR

  • 元ネタはこちら

0. ゴールの確認

  • 「ずん」「どこ」「き・よ・し!」の出力はすべてreceiveValueで受け取るStringとする(= assignしようと思えばできる状態を目指す)。記事ではinput:○○○○○○で表現する。
  • Publisherのprint(_:to:)はデバグ用に使う(回答としてカウントしない)
  • 一度「き・よ・し!」を出力したら処理を終了する

1. ずんどこ川の水源を作る

まずは「ずん」または「どこ」が湧き出る水源を作っていく。
勢いよく湧き出て欲しいので、0.1秒間隔で出力していこう。

iOS 13から追加されたTimer.publish(every:tolerance:on:in:options:)を使っていく。

    let ずんどこ水源 =
        Timer.publish(every: 0.1, on: .main, in: .default)
            .autoconnect()
            .map { _ in Int.random(in:0..<2) == 0 ? "ずん" : "どこ" }
            .share()

    self.cancellable =
        ずんどこ水源
        .sink(receiveCompletion: { _ in
            print("===完===")
        }, receiveValue: {
            print("input: \($0)")
        })

結果はこちら。
zundoko-fountain

良い。すごく良い。勢いある湧出量だ。

2. センサー付きの水門づくり

上述のとおり、ずんどこ水源からは「ずん」または「どこ」が1語ずつ流れてくる。

検知したいのは「ずん、ずん、ずん、ずん、どこ」の5要素なので、FIFO方式でずんどこが5つだけたまる溜池を作る。
そして、溜まった要素がお目当てのパターンか判定するセンサーを作る。
もしパターンを検知できたら水門を閉じる。
いたずらにずんどこを溜めない。

    let センサー付き水門 =
        ずんどこ水源
            .scan([], { (reservoir: [String], element: String) -> [String] in
                // 溜池
                var newReservoir = Array(reservoir + [element])
                if newReservoir.count > 5 {
                    newReservoir.removeFirst()
                }
                return newReservoir.prefix(5).map { $0 }
            })
            .allSatisfy { $0 != ["ずん", "ずん", "ずん", "ずん", "どこ"] }
            .map { _ in  }
            .share()

3. 検知後「き・よ・し!」を知らせる

()が流れてくる仕組みを活用し、「き・よ・し!」と流れるスピーカーを作ろう。

   let スピーカー = センサー付き水門.map { _ in "き・よ・し!" }

これでも悪くはない。

しかし、贅沢を言えば「どこ」と「き・よ・し!」の間には"ため"が欲しい。
そこで1秒くらい"ため"を作ろう。
結果には影響を与えない形で"ため"を確認できるようprintしておこう。

    let スピーカー = センサー付き水門.map { _ in "き・よ・し!" }
                                .handleEvents(receiveOutput: { _ in
                                    print("(せーの...!)")
                                })
                                .delay(for: .seconds(1.0), scheduler: RunLoop.main)

4. 整備されたずんどこ川の全貌

野川状態だった、ずんどこ川にも必要な設備が揃った。
あとはこれらをうまく組み合わせていく。
これで、河川管理もバッチリだ。

let ずんどこ水源 =
    Timer.publish(every: 0.1, on: .main, in: .default)
        .autoconnect()
        .map { _ in Int.random(in:0..<2) == 0 ? "ずん" : "どこ" }
        .share()

let センサー付き水門 =
    ずんどこ水源
        .scan([], { (reservoir: [String], element: String) -> [String] in
            // 溜池
            var newReservoir = Array(reservoir + [element])
            if newReservoir.count > 5 {
                newReservoir.removeFirst()
            }
            return newReservoir.prefix(5).map { $0 }
        })
        .allSatisfy { $0 != ["ずん", "ずん", "ずん", "ずん", "どこ"] }
        .map { _ in  }
        .share()

let スピーカー = センサー付き水門.map { _ in "き・よ・し!" }
                            .handleEvents(receiveOutput: { _ in
                                print("(せーの...!)")
                            })
                            .delay(for: .seconds(1.0), scheduler: RunLoop.main)

self.cancellable =
    ずんどこ水源
    .prefix(untilOutputFrom: センサー付き水門) // センサーが検知するまで、ずんどこを流す
    .merge(with: スピーカー) // 検知したら、き・よ・し!を流す
    .sink(receiveCompletion: { _ in
        print("===完===")
    }, receiveValue: {
        print("input: \($0)")
    })

よし、最後にこれを動かしてみよう。
...

....

.....

output

💪💪💪💪💪💪💪💪💪💪💪💪💪💪💪

あとがき

ふざけているようですが、トライしてみるとオペレーターの挙動に詳しくなります
もっと良い実装例があったら@mshrwtnbまで教えていただけると勉強になります
https://github.com/mshrwtnb/zundoko-combine にソースを置きました。

以上

Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away