Swift開発手法をポケモンで理解してみよう⑤

ポケモンニワカなのでポケモンに関する情報は正確ではない可能性があります、ご容赦ください。

Swift開発手法をポケモンに例えて覚えてみようとする試み。

Part5 & RxSwift編です。(SwiftUIが主流な今Outdatedかもですが)

Part5

map, flatMap

進化の石、ムーンストーン (map) , 進化の奇跡、メガシンカ (flatMap)

解説

1. map

  • タイプ: いわ (イベントを別の形に変化させる、いわタイプのように硬い意志を表現)
  • 特性: ふゆう (他の要素に影響を受けずに、独立してイベントを変換)
  • 得意技:
    • パワーストーン: イベントの価値を高める
    • げんしのちから: イベントに新たな力を与える
    • ロックカット: 不要な部分を削り、イベントを洗練させる
  • 性格: まじめ (決められたルールに従って、正確に変換)

ムーンストーンのように、mapは:

  • Observableの要素の型を変更したい場合に便利です。
  • イベントを別の形のイベントに変換します。
  • 各イベントを個別に処理し、新しいイベントのストリームを作成します。
let pokedex = Observable.of("ニドラン♀", "ニドリーナ", "ニドクイン")

pokedex
    .map { pokemon in
        return "\(pokemon) (どく/じめん)" // タイプ情報を追加
    }
    .subscribe(onNext: { pokemonWithTypes in
        print(pokemonWithTypes)
    })
    .disposed(by: disposeBag)

2. flatMap

  • タイプ: ドラゴン (複数のObservableを1つのストリームに統合する、強力な力を表現)
  • 特性: メガシンカ (一時的に能力が向上するように、Observableを別のObservableに変換)
  • 得意技:
    • りゅうせいぐん: 複数のObservableから強力なイベントを生成
    • ドラゴンダイブ: 複雑なイベントの流れを1つにまとめる
    • げきりん: 最後までイベントを出し続ける
  • 性格: ゆうかん (恐れずに新しいObservableに挑戦)

メガシンカのように、flatMapは:

  • イベントを別のObservableに変換し、そのObservableのイベントを元のストリームに統合します。
  • ネストされたObservableを平坦化し、1つのストリームとして扱えます。
  • イベントの発生源を動的に変更したい場合に便利です。
let pokemon = Observable.of("フシギダネ", "ヒトカゲ", "ゼニガメ")

pokemon
    .flatMap { pokemon in
        return Observable.of("\(pokemon)ゲットだぜ!", "\(pokemon)を育てる") // 進化後のイベントを生成
    }
    .subscribe(onNext: { message in
        print(message)
    })
    .disposed(by: disposeBag)

debounce

冷静沈着なサーナイト

解説
  • タイプ: エスパー/フェアリー (イベントの発生を察知し、適切なタイミングで行動する能力を表現)
  • 特性: トレース (相手の特性をコピーするように、イベントの発生間隔を調整)
  • 得意技:
    • みらいよち: イベントの発生を予測し、準備を整える
    • めいそう: 集中力を高め、正確なタイミングでイベントを処理
    • マジカルシャイン: 不要なイベントを消し去り、重要なイベントだけを残す
  • 性格: おだやか (冷静に状況を判断し、適切な行動を選択)

サーナイトのように、debounceは:

  • 指定した時間内に連続して発生するイベントを無視し、最後のイベントのみを通過させます。
  • チャタリングのような頻繁なイベントを抑制し、パフォーマンスを向上させます。
  • テキスト入力の検索処理やボタンの連打対策などに有効です。
let searchBar = UISearchBar()

searchBar.rx.text // 検索テキストのObservable
    .orEmpty // nilを空文字列に変換
    .debounce(.milliseconds(500), scheduler: MainScheduler.instance) // 0.5秒間イベントを遅延
    .distinctUntilChanged() // 前回のイベントと同じ場合は無視
    .subscribe(onNext: { query in
        print("検索: \(query)") // 検索処理を実行
    })
    .disposed(by: disposeBag)
  • searchBar.rx.text で検索テキストのObservableを取得します。
  • orEmpty でnilを空文字列に変換します。
  • debounce(.milliseconds(500), scheduler: MainScheduler.instance) で0.5秒間イベントを遅延させます。
  • distinctUntilChanged() で前回のイベントと同じ場合は無視します。
  • subscribe(onNext:) でイベントを購読し、検索処理を実行します。
  • disposed(by: disposeBag) で購読を破棄します。

RxSwiftの世界では、debounceは冷静沈着なサーナイト。

慌てず騒がず、適切なタイミングでイベントを処理することで、スムーズなユーザー体験を提供します。


distinctUntilChanged

変化を見抜くメタモン

解説
  • タイプ: ノーマル (どんなタイプのイベントにも対応できる柔軟性)
  • 特性: かわりもの (前のイベントと比較し、変化があった場合のみ反応)
  • 得意技:
    • へんしん: 前のイベントの状態を記憶
    • ものまね: 変化したイベントのみを伝える
    • かげぶんしん: 同じイベントを複数回処理することを防ぐ
  • 性格: まんぷく (変化がない限り、エネルギーを消費しない)

メタモンのように、distinctUntilChangedは:

  • 連続して同じ値のイベントを無視し、値が変化したときのみイベントを伝播させます。
  • UIの不要な更新を防ぎ、パフォーマンスを向上させます。
  • 例えば、検索バーの入力値の変化を監視する場合などに有効です。
let pokedex = BehaviorSubject(value: "ピカチュウ")

pokedex
    .distinctUntilChanged() // 値が変化したときのみイベントを伝える
    .subscribe(onNext: { pokemon in
        print("ポケモンが\(pokemon)に変化した!")
    })
    .disposed(by: disposeBag)

pokedex.onNext("ピカチュウ") // 変化なし
pokedex.onNext("ライチュウ") // 変化あり
pokedex.onNext("ライチュウ") // 変化なし
  • BehaviorSubject(value: "ピカチュウ") で初期値 “ピカチュウ” のBehaviorSubjectを作成します。
  • distinctUntilChanged() で値が変化したときのみイベントを伝えるようにします。
  • subscribe(onNext:) でイベントを購読し、ポケモンの変化を出力します。
  • onNext で値を更新しますが、2回目は同じ値なのでイベントは伝播されません。

RxSwiftの世界では、distinctUntilChangedは変化を見抜くメタモン。

変化のないイベントを無視することで、効率的に情報を処理し、無駄な処理を省きます。


combineLatest

協力プレイのレジギガス

解説
  • タイプ: ノーマル (様々なタイプのObservableを組み合わせる)
  • 特性: スロースタート (最初はゆっくりだが、徐々に力を発揮)
  • 得意技:
    • ワイドガード: 全てのObservableからのイベントを待ち受ける
    • はかいこうせん: 全てのObservableから最新の値を受け取り、強力なイベントを生成
    • ロックオン: 常に最新の値に注目
  • 性格: がんばりや (最後まで諦めずにイベントを待つ)

レジギガスのように、combineLatestは:

  • 複数のObservableを組み合わせ、全てのObservableから少なくとも1つずつ値が発行された後にイベントを生成します。
  • 各Observableの最新の値を組み合わせて新しいイベントを作成します。
  • 例えば、複数のフォームの入力値を組み合わせてバリデーションを行う場合などに便利です。
let pokeBall = Observable.of("モンスターボール", "スーパーボール", "ハイパーボール")
let pokemon = Observable.of("ピカチュウ", "イーブイ", "フシギダネ")

Observable.combineLatest(pokeBall, pokemon) { ball, pokemon in
    return "\(ball)で\(pokemon)をゲット!"
}
.subscribe(onNext: { message in
    print(message)
})
.disposed(by: disposeBag)

zip

コンビネーションのルガルガン (まひるのすがた/まよなかのすがた)

解説
  • タイプ: いわ/あく (複数のObservableを1対1で組み合わせる)
  • 特性: かたいツメ/すなかき (それぞれのObservableの特性を尊重)
  • 得意技:
    • アクセルロック: 2つのObservableのイベントを同時に処理
    • いわなだれ/かみくだく: それぞれのObservableのイベントを組み合わせて新しいイベントを生成
    • カウンター/インファイト: 相手のObservableに合わせた柔軟な対応
  • 性格: ゆうかん/いじっぱり (自分のペースを崩さずにイベントを処理)

ルガルガン (まひるのすがた/まよなかのすがた) のように、zipは:

  • 複数のObservableを1対1で組み合わせ、同時に発生したイベントのみを新しいイベントとして生成します。
  • 各Observableのイベントの順番を保ちます。
  • 例えば、2つのAPIからのレスポンスを組み合わせて処理する場合などに便利です。
let trainer = Observable.of("サトシ", "カスミ", "タケシ")
let pokemon = Observable.of("ピカチュウ", "トゲピー", "ロコン")

Observable.zip(trainer, pokemon) { trainer, pokemon in
    return "\(trainer)と\(pokemon)のコンビ!"
}
.subscribe(onNext: { message in
    print(message)
})
.disposed(by: disposeBag)

merge

自由気ままなフリーザー

解説
  • タイプ: こおり/ひこう (複数のObservableを1つのストリームにまとめる、自由な流れを表現)
  • 特性: プレッシャー (他のObservableに影響を与えず、自分のペースでイベントを発行)
  • 得意技:
    • ふぶき: 複数のObservableからイベントをまとめて放出
    • こごえるかぜ: イベントの順番を制御
    • オーロラベール: ストリーム全体を保護
  • 性格: むじゃき (自由にイベントを発行)

フリーザーのように、mergeは:

  • 複数のObservableを1つのストリームにまとめます。
  • 各Observableのイベントの発生順序は保証されません。
  • 例えば、複数のボタンのタップイベントを1つのストリームで処理する場合などに便利です。
let button1 = UIButton()
let button2 = UIButton()

let button1Taps = button1.rx.tap.map { "ボタン1がタップされた" }
let button2Taps = button2.rx.tap.map { "ボタン2がタップされた" }

Observable.merge(button1Taps, button2Taps)
    .subscribe(onNext: { message in
        print(message)
    })
    .disposed(by: disposeBag)