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

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

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

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

Part4

Observable (全般)

様々な技を使いこなす変幻自在のピカチュウ

解説

1. ピカチュウの特性に例えてみる

  • タイプ: でんき (イベントの流れを電流に例え、様々な可能性を表現)
  • 特性: せいでんき (触れた相手に影響を与えるように、イベントを発行)
  • 得意技:
    • 10まんボルト: 強力なイベントを次々と発生させる
    • でんこうせっか: 素早くイベントを伝える
    • ボルテッカー: 時に予想外のイベント (エラー) を発生させることも
  • 性格: ようき (活発にイベントを発行し、状況に応じて変化)

ピカチュウのように、Observableは:

イベントの完了、エラーの発生など、様々な状態を表現できます。

様々な種類のイベントを次々と発生させることができます。

イベントの流れを自由に操作し、加工することができます。

let observable = Observable.of("ピカチュウ", "ライチュウ", "ピチュー") // 文字列のイベントを発生させるObservable

observable
    .subscribe(onNext: { name in
        print(name + "が現れた!") // イベントを受け取って処理
    }, onError: { error in
        print("エラーが発生した!: \(error)") // エラーが発生した場合の処理
    }, onCompleted: {
        print("イベントが完了した!") // イベントが完了した場合の処理
    })
    .disposed(by: disposeBag)
  • Observable.of(...) で文字列のイベントを発生させるObservableを作成します。
  • subscribe(onNext:onError:onCompleted:) でObservableを購読し、イベントを受け取るたびにonNextクロージャが実行されます。
  • エラーが発生した場合はonErrorクロージャ、イベントが完了した場合はonCompletedクロージャが実行されます。
  • disposed(by: disposeBag) で購読を破棄し、メモリリークを防ぎます。

Single

一撃必殺のカイリキー

解説
  • タイプ: かくとう (一度きりのイベントを強力なパンチに見立てて表現)
  • 特性: ノーガード (必ずイベントを成功させるか、失敗するかのどちらか)
  • 得意技:
    • ばくれつパンチ: 成功または失敗のどちらかしかない強力なイベントを表す
    • クロスチョップ: 成功した場合に大きな効果をもたらすイベント
    • ビルドアップ: イベントが発生する前に準備を行う
  • 性格: いじっぱり (成功を信じて突き進む)

カイリキーのように、Singleは:

  • 1回だけイベントを発生させます (成功または失敗)。
  • 成功した場合に値を返し、失敗した場合はエラーを発生させます。
  • ネットワークリクエストやデータベースの読み込みなど、結果が1つしかない処理に適しています。
let single = Single<String>.create { single in
    // 何かしらの処理 (成功 or 失敗)
    let success = true // ここでは成功を想定

    if success {
        single(.success("成功!")) // 成功した場合
    } else {
        single(.failure(NSError(domain: "ErrorDomain", code: -1, userInfo: nil))) // 失敗した場合
    }

    return Disposables.create()
}

single
    .subscribe(onSuccess: { message in
        print(message) // 成功した場合の処理
    }, onFailure: { error in
        print("エラー: \(error)") // 失敗した場合の処理
    })
    .disposed(by: disposeBag)
  • Single<String>.create でSingleを作成し、クロージャ内で何らかの処理を行います。
  • 処理が成功した場合はsingle(.success(値))、失敗した場合はsingle(.failure(エラー))を呼び出します。
  • subscribe(onSuccess:onFailure:) でSingleを購読し、成功または失敗に応じて処理を行います。
  • disposed(by: disposeBag) で購読を破棄します。

Driver

安全運転のギャラドス

解説
  • タイプ: みず/ひこう (イベントの流れを水の流れに例え、UIへの安全な反映を空への飛行で表現)
  • 特性: いかく (エラーを寄せ付けない強さを表現)
  • 得意技:
    • たきのぼり: UIイベントを力強く、そして確実に伝える
    • とびはねる: メインスレッドで安全にUIを更新
    • りゅうのまい: 常に安定した状態を保ち、UIを安全に更新し続ける
  • 性格: しんちょう (慎重にイベントを処理し、UIを確実に更新)

ギャラドスのように、Driverは:

  • UIイベントを安全に扱い、UIの更新を確実に行います。
  • エラーを発生させず、常に安定した状態を保ちます。
  • メインスレッドで動作し、UIをスムーズかつ安全に更新します。
  • イベントを共有し、効率的にUIの更新を行います。
let button = UIButton()
let driver = button.rx.tap // タップイベントをDriverに変換
    .asDriver() // エラーが発生しないことを保証

driver
    .drive(onNext: { _ in
        // UIの更新処理 (安全に実行)
    })
    .disposed(by: disposeBag)
  • button.rx.tap でボタンのタップイベントをObservableとして取得します。
  • asDriver() でObservableをDriverに変換し、エラーが発生しないことを保証します。
  • drive(onNext:) でDriverのイベントを購読し、UIの更新処理を安全に実行します。
  • disposed(by: disposeBag) で購読を破棄し、メモリリークを防ぎます。

BehaviorRelayとPublishRelay

イベント配信の名人ポケモン

解説

1. BehaviorRelay (フーディン)

  • タイプ: エスパー (現在の値を記憶し、新しいイベントを伝える能力を表現)
  • 特性: シンクロ (他のポケモンと状態を共有する能力を表現)
  • 得意技:
    • サイコキネシス: 現在の値を保持し、それを伝える
    • ゆめくい: 過去の値を記憶し、必要に応じて取り出す
    • バリアー: 値の変化を安全に管理
  • 性格: せっかち (すぐに新しい値を受け取り、伝える)

フーディンのように、BehaviorRelayは:

  • 現在の値を常に保持し、新しい購読者にもその値を伝えます。
  • 値が更新されると、全ての購読者に新しい値を通知します。
  • 値の変更履歴を保持しませんが、常に最新の値にアクセスできます。
let pokedex = BehaviorRelay<[String]>(value: ["フシギダネ", "ヒトカゲ", "ゼニガメ"])

pokedex.accept(["ピカチュウ", "イーブイ"]) // 新しいポケモンを追加

pokedex.asObservable()
    .subscribe(onNext: { pokemon in
        print("ゲットだぜ!\(pokemon)")
    })
    .disposed(by: disposeBag)

2. PublishRelay (ミュウ)

  • タイプ: エスパー (様々なイベントを受け取り、伝える能力を表現)
  • 特性: シンクロ (他のポケモンとイベントを共有する能力を表現)
  • 得意技:
    • はどうだん: 新しいイベントを次々と発生させる
    • テレポート: イベントを瞬時に伝える
    • みらいよち: イベントの発生を予測
  • 性格: おっとり (イベントを冷静に受け止め、伝える)

ミュウのように、PublishRelayは:

  • 新しいイベントが発生するたびに、それを購読者に通知します。
  • 過去のイベントを保持せず、常に最新のイベントに焦点を当てます。
  • 値の概念を持たず、イベントの発生のみを扱います。
let trainerActions = PublishRelay<String>()

trainerActions.accept("モンスターボールを投げる")
trainerActions.accept("ポケモンをゲット")

trainerActions.asObservable()
    .subscribe(onNext: { action in
        print(action)
    })
    .disposed(by: disposeBag)

DisposeBag

整理整頓のヨクバリス

解説
  • タイプ: ノーマル (どんなタイプのObservable/Disposableも受け入れる)
  • 特性: ほおぶくろ (たくさんのアイテムをしまっておけるように、たくさんのDisposableを保持)
  • 得意技:
    • たくわえる: Disposableを安全に保管
    • リサイクル: 不要になったDisposableを自動で処分
    • おんがえし: プロジェクトをクリーンに保つ
  • 性格: きちょうめん (几帳面にDisposableを管理)

ヨクバリスのように、DisposeBagは:

  • Observableの購読を解除するためのDisposableをまとめて管理します。
  • 自身が破棄される際に、保持している全てのDisposableを自動的にdisposeします。
  • メモリリークを防ぎ、プロジェクトをクリーンに保ちます。
let disposeBag = DisposeBag() // ヨクバリスの登場!

observable
    .subscribe(onNext: { pokemon in
        print("ゲットだぜ!\(pokemon)")
    })
    .disposed(by: disposeBag) // ヨクバリスにDisposableを預ける

// disposeBagが破棄されると、自動的に購読が解除される
  • DisposeBag() でDisposeBagを作成します。
  • subscribe() の戻り値であるDisposableを disposed(by: disposeBag) に渡すことで、DisposeBagにDisposableを登録します。
  • DisposeBagがスコープから外れて破棄されると、自動的に登録されている全てのDisposableがdisposeされ、購読が解除されます。