ポケモンニワカなのでポケモンに関する情報は正確ではない可能性があります、ご容赦ください。
Swift開発手法をポケモンに例えて覚えてみようとする試み。
Part8、今回はCombine系です。
Contents 非表示
Part8
AnyCancellable
購読解除のエキスパート、バクフーン
解説
- タイプ: ほのお (不要な購読を燃やし尽くす)
- 特性: もうか (購読解除を忘れると危険な状態になる)
- 得意技:
- かえんほうしゃ: 不要な購読を強力に解除
- フレアドライブ: 購読解除を確実に行う
- にほんばれ: 購読解除のタイミングを制御
- 性格: まじめ (几帳面に購読を管理)
バクフーンのように、AnyCancellable
は:
- Combineのパブリッシャーの購読を管理し、必要に応じて解除するための機能です。
- 購読を解除することで、メモリリークや不要な処理を防ぎます。
- 購読を適切に管理することで、Combineを安全かつ効率的に利用できます。
var subscriptions = Set<AnyCancellable>()
let pokemonPublisher = ["ピカチュウ", "イーブイ", "フシギダネ"].publisher
pokemonPublisher
.sink(receiveValue: { pokemon in
print("ゲットだぜ!\(pokemon)")
})
.store(in: &subscriptions) // 購読をsubscriptionsに登録
Set<AnyCancellable>()
で購読を管理するためのSetを作成します。pokemonPublisher.sink
でパブリッシャーを購読し、値を受け取るたびに “ゲットだぜ![ポケモン名]” と出力します。.store(in: &subscriptions)
で購読をsubscriptions
に登録します。- これにより、
subscriptions
がスコープ外になったときに自動的に購読が解除されます。
receive(on:options:)
空間転送のミュウツー
解説
- タイプ: エスパー (他のスレッドやキューに情報を転送する能力を表現)
- 特性: プレッシャー (他の処理に影響を与えず、自分のペースで転送)
- 得意技:
- テレポート: 値を別のスレッドやキューに瞬時に転送
- サイコキネシス: 転送先のキューを操作し、処理の順序を制御
- バリアー: 転送中の値を保護し、安全性を確保
- 性格: れいせい (冷静に状況を判断し、最適な転送先を選択)
ミュウツーのように、receive(on:options:)
は:
- パブリッシャーから受け取った値を、指定したスレッドまたはキューで処理できるようにします。
- UIの更新はメインスレッドで行う必要があるため、UI関連の処理をメインスレッドに転送する際に使用します。
- バックグラウンドスレッドで実行された処理結果をメインスレッドに転送してUIを更新する際にも利用されます。
let backgroundQueue = DispatchQueue(label: "background")
["ピカチュウ", "イーブイ", "フシギダネ"].publisher
.receive(on: backgroundQueue) // バックグラウンドキューで処理
.map { pokemon in
// 重たい処理 (例: 画像のダウンロード)
return pokemon.uppercased()
}
.receive(on: DispatchQueue.main) // メインスレッドで処理
.sink(receiveValue: { pokemon in
print(pokemon) // 結果をUIに反映
})
.store(in: &subscriptions)
backgroundQueue
というバックグラウンドキューを作成します。receive(on: backgroundQueue)
で、パブリッシャーからの値をバックグラウンドキューで処理するようにします。map
演算子で、受け取ったポケモン名を大文字に変換する処理をバックグラウンドキューで実行します。receive(on: DispatchQueue.main)
で、処理結果をメインスレッドに転送します。sink
でメインスレッドで受け取った値を処理し、UIに結果を反映します。
sink(receiveCompletion:receiveValue:)
イベントキャッチの名人、ヌオー
解説
- タイプ: みず/じめん (様々なイベントを受け止め、大地に根を張る安定感を表現)
- 特性: ちょすい/てんねん (完了と値のイベントを確実に受け取る)
- 得意技:
- あまごい: パブリッシャーからのイベントを呼び込む
- じしん: 受け取った値をしっかりと処理
- カウンター: エラーが発生した場合の対応
- 性格: のんき (焦らずイベントを待ち、確実に処理)
ヌオーのように、sink(receiveCompletion:receiveValue:)
は:
- パブリッシャーからのイベントを購読し、完了と値のイベントを受け取るために使用されます。
- 完了イベント (
finished
) または失敗イベント (failure(Error)
) が発生すると、購読は自動的にキャンセルされます。 - Combineで最も基本的な購読方法であり、様々な場面で使用されます。
let pokemonPublisher = ["フシギダネ", "ヒトカゲ", "ゼニガメ"].publisher
pokemonPublisher
.sink(
receiveCompletion: { completion in
switch completion {
case .finished:
print("ポケモンゲット完了!")
case .failure(let error):
print("エラーが発生しました: \(error)")
}
},
receiveValue: { pokemon in
print("ゲットだぜ!\(pokemon)")
}
)
.store(in: &subscriptions)
pokemonPublisher
というパブリッシャーを作成します。sink(receiveCompletion:receiveValue:)
でパブリッシャーを購読します。receiveCompletion
クロージャーで完了イベント (finished
) または失敗イベント (failure(Error)
) を受け取ります。receiveValue
クロージャーでパブリッシャーから送信された値を受け取ります。.store(in: &subscriptions)
で購読をsubscriptions
に登録します。
assign(to:on:)
プロパティ変更の使い手、エーフィ
解説
- タイプ: エスパー (オブジェクトのプロパティを直接変更する能力を表現)
- 特性: シンクロ (パブリッシャーの値とオブジェクトのプロパティを同期)
- 得意技:
- サイコキネシス: プロパティの値を直接変更
- リフレクター: 不正な値の代入を防ぐ
- スキルスワップ: 他のオブジェクトと連携してプロパティを変更
- 性格: おだやか (冷静に値を受け取り、プロパティに代入)
エーフィのように、assign(to:on:)
は:
- パブリッシャーから受け取った値を、オブジェクトのKeyPathで指定されたプロパティに直接代入します。
- UIの更新や状態管理など、プロパティの値を動的に変更したい場合に便利です。
- KVO (Key-Value Observing) のような仕組みをCombineで実現できます。
class PokemonViewModel {
@Published var name: String = ""
}
let viewModel = PokemonViewModel()
let pokemonPublisher = ["ピカチュウ", "イーブイ", "フシギダネ"].publisher
pokemonPublisher
.assign(to: \.name, on: viewModel) // viewModel.nameに値を代入
.store(in: &subscriptions)
PokemonViewModel
クラスを作成し、@Published
プロパティname
を定義します。viewModel
というインスタンスを作成します。pokemonPublisher
というパブリッシャーを作成します。assign(to: \.name, on: viewModel)
で、パブリッシャーから受け取った値をviewModel.name
に代入するように設定します。.store(in: &subscriptions)
で購読をsubscriptions
に登録します。
@Published
変化を知らせるムチュール
解説
- タイプ: エスパー (心を読む能力のように、プロパティの変化を検知し、外部に通知する)
- 特性: ちょすい/よちむ (変更を確実に検知し、準備を整える)
- 得意技:
- みらいよち: プロパティの変更を予測し、購読者に通知
- バトンタッチ: 変更された値を他のオブジェクトに安全に渡す
- あまえる: Viewに自身の変更を可愛らしくアピール
- 性格: おだやか (慌てず騒がず、変更を確実に通知)
ムチュールのように、@Published
は:
- プロパティの変化を監視し、変更があった際に自動的にパブリッシャーを生成します。
- このパブリッシャーを通じて、他のオブジェクト(主にView)はプロパティの変化を購読し、それに応じて自身の状態を更新できます。
- SwiftUIにおけるリアクティブプログラミングの中核を担い、データの変化に応じてUIを動的に更新する仕組みを提供します。
class Pokemon: ObservableObject {
@Published var name: String = "ピカチュウ"
@Published var level: Int = 10
}
struct ContentView: View {
@ObservedObject var pokemon = Pokemon()
var body: some View {
VStack {
Text("名前: \(pokemon.name)")
Text("レベル: \(pokemon.level)")
Button("進化!") {
pokemon.name = "ライチュウ"
pokemon.level += 10
}
}
}
}
Pokemon
クラスはObservableObject
プロトコルに準拠し、@Published
でマークされたプロパティname
とlevel
を持ちます。ContentView
は@ObservedObject
でPokemon
のインスタンスを保持します。body
内でpokemon.name
とpokemon.level
を表示し、ボタンがタップされるとこれらの値が更新されます。@Published
のおかげで、プロパティの変更が自動的に検知され、Viewが再描画されて最新の値が表示されます。