ソフトウェア設計

Swiftのオブザーバーパターン:NotificationCenterからCombineまで

iOSアプリを作っていると、画面Aで何かが変わり、遠く離れた画面Bも更新しなければならない場面に必ず出会います。

読了 4 分
Swiftのオブザーバーパターン:NotificationCenterからCombineまでのカバー画像

iOSアプリを作っていると、画面Aで何かが変わり、遠く離れた画面Bも更新しなければならない場面に必ず出会います。

画面同士をデリゲートで無理につなぐと、コードはスパゲッティのように絡まりやすくなります。

そんなときに使うのがオブザーバーパターンです。SwiftではNotificationCenterから始め、Combineへ移行する流れが最も自然です。

この記事では、オブザーバーパターンの概要からNotificationCenterの使い方、最近よく使われるCombineまで、実際のコードとともに整理します。

オブザーバーパターンとは?

オブザーバーパターンとは、ある対象の状態が変わると、それを監視しているオブジェクトへ自動的に通知する構造です。

YouTubeのチャンネル登録を思い浮かべると分かりやすいでしょう。チャンネル(発行者)が動画を投稿すると、登録者(オブザーバー)に通知が届きます。

重要なのは、発行者とオブザーバーが互いを直接知らなくてもよい点です。

発行者とオブザーバーは互いを知らず、通知だけをやり取りします
発行者とオブザーバーは互いを知らず、通知だけをやり取りします

チャンネルは登録者の人数や誰が登録しているかを気にしません。ただ「動画を投稿した」と知らせるだけです。

このように疎結合にするとコードが絡まりにくく、後からの修正もずっと楽になります。


NotificationCenterはどう使う?

NotificationCenterはAppleが標準で提供するオブザーバーパターンのツールです。追加のライブラリなしですぐ使えます。

まず通知名を定義し、発行側のコードを書きます。

// 通知名の定義
extension Notification.Name {
    static let didLogin = Notification.Name("didLogin")
}

// ログイン成功時に通知を発行
NotificationCenter.default.post(name: .didLogin, object: nil)

受信側では、次のようにオブザーバーを登録します。

// 通知を購読
NotificationCenter.default.addObserver(
    self, selector: #selector(handleLogin),
    name: .didLogin, object: nil
)

注意点が一つあります。従来の方法(addObserver + selector)は、画面が消えるときにremoveObserverを呼ばないと問題になることがあります。

iOS 9以降は自動で解放される部分が増えましたが、ブロックベースのAPIでは返されたトークンの管理が必要です。


Combineに移行すると何がよい?

CombineはAppleが2019年に発表したリアクティブプログラミングフレームワークです。iOS 13以降で利用できます。

NotificationCenterはCombineのPublisherにも変換できるため、既存コードとも自然に組み合わせられます。

// NotificationCenterを Combine 方式に
let token = NotificationCenter.default
    .publisher(for: .didLogin)
    .sink { _ in
        print("ログインを検知!")
    }

Combineの本当の強みは、データの流れをつなげられることです。

mapやfilterなどの演算子で値を加工したり、複数のイベントをまとめたりできます。

sinkが返す購読(AnyCancellable)を変数に保持しておけば、その変数が破棄されたときに購読も自動でキャンセルされます。メモリ管理がずっと楽になります。

私はコードを表示したまま手を動かして書き、感覚をつかみました
私はコードを表示したまま手を動かして書き、感覚をつかみました

結局、何を使えばよい?

状況によって異なります。下の表にまとめました。

項目 NotificationCenter Combine
導入時期 古い標準API iOS 13+
学習難易度 低い 中以上
値の加工 難しい map/filterで自由に
メモリ管理 手動で対応 購読を保持すれば自動

簡単な通知が1、2個ならNotificationCenterで十分です。

一方、データの流れが複雑だったり、複数のイベントを組み合わせたりするならCombineのほうがはるかにすっきりします。

初めてならNotificationCenterで概念を学び、慣れたらCombineへ進みましょう。

もちろん最近はSwiftUIとasync/awaitが主流なので、新規プロジェクトではこの2つも一緒に検討することをおすすめします。

通知が一つ届いた瞬間に別の画面まで更新されると、とても達成感があります
通知が一つ届いた瞬間に別の画面まで更新されると、とても達成感があります

まとめ

今日はSwiftのオブザーバーパターンを、NotificationCenterからCombineまで見てきました。

最初から完璧に理解しようとせず、まずは小さな通知を一つ自分で作ってみてください。手を動かすと、ずっと早く感覚をつかめます。応援しています!

あわせて読みたい