Combineを使ってみて分かったこと

Combineを使ってみて分かったこと 学習記録

CloudKitでのiCloud同期を実装する中で、検索欄への入力に応じてリアルタイムで検索結果を絞り込みたい場面があり、Combineというフレームワークの存在を思い出して使ってみることにしました。

1. PublisherとSubscriberという言葉に身構えた

ドキュメントを読み始めると、「Publisher(発行者)」「Subscriber(購読者)」という聞き慣れない言葉が並び、最初は身構えてしまいました。

Publisher: 値の変化を流す側
Subscriber: その値を受け取って処理する側

整理してみると、「値が変わるたびにお知らせしてくれる仕組み」と「そのお知らせを受け取って何かする仕組み」という、意外とシンプルな役割分担だと分かりました。専門用語に惑わされず、まず日本語で役割を言い換えてみるのが理解の近道でした。

2. 検索欄の入力を間引く処理が数行で書けた

検索欄に文字を入力するたびに毎回検索処理を走らせるのは無駄が多いと感じていたのですが、Combineのdebounceという仕組みを使うと、入力が落ち着いてから一定時間後にだけ処理を実行できると知りました。

$searchText
    .debounce(for: .milliseconds(300), scheduler: RunLoop.main)
    .sink { text in
        performSearch(text)
    }

これまで自前でタイマーを組んで似たような処理を書こうとして挫折した経験があったのですが、Combineが用意している仕組みを使うだけで、驚くほど簡潔に実現できました。

3. 購読を解除し忘れてメモリリークを起こした

一通り動くようになって満足していたのですが、しばらくしてメモリの使用量が増え続けていることに気づきました。

private var cancellables = Set<AnyCancellable>()

$searchText
    .sink { text in performSearch(text) }
    .store(in: &cancellables)

購読を開始した処理(sink)をcancellablesという入れ物に保持し、画面が破棄されるタイミングで自動的に解除されるようにする必要があると知りました。購読を開始しっぱなしで解除を意識していなかったことが、メモリリークの原因でした。

4. async/awaitとの使い分けに迷った

async/awaitへの書き換えを経験していたこともあり、「非同期処理はasync/awaitで統一すべきでは」と迷う場面がありました。

調べた結果、一回きりの非同期処理(通信結果を1回だけ受け取る、など)はasync/awaitが向いており、時間の経過とともに何度も値が変化し続けるもの(テキストフィールドの入力、通知の購読など)はCombineが向いていると整理できました。「どちらか一方に統一する」のではなく、扱うデータの性質によって使い分けるものだと理解しました。

まとめ

  • PublisherとSubscriberは「値の変化を流す側」と「それを受け取る側」という役割分担だと理解すると分かりやすい
  • debounceのような仕組みを使うと、連続する入力の間引き処理を数行で実現できる
  • 購読はcancellablesに保持し、画面破棄時に解除されるようにしないとメモリリークの原因になる
  • 一回きりの非同期処理はasync/await、継続的に変化する値の監視はCombineという使い分けが実用的

新しい概念を覚えるハードルはありましたが、実際に手を動かしてみると「便利な道具が一つ増えた」という感覚に近く、想像していたよりも早く馴染めました。

次は、AdMobでバナー広告を導入してみた話をまとめます。


本記事は生成AI(Claude)を活用して執筆・編集しています。内容は実体験に基づき、執筆者本人が確認・監修しています。

コメント

タイトルとURLをコピーしました