
SwiftUIでアプリを開発していると、
- 「商品をカートに追加した時に、ナビゲーションバーのカートアイコンも同時に更新したい」
- 「ユーザーがログインした瞬間に、複数の画面で表示を変更したい」
といった場面に遭遇することがあります。
このような「離れた場所にあるコンポーネント同士で情報をやり取りしたい」という課題を解決してくれるのが、NotificationCenter.default.post
です。
この記事では、NotificationCenter.default.postの基本的な仕組みから実際の使用方法、指定できるオプションまで、わかりやすく解説していきます。
NotificationCenter.default.postとは
NotificationCenter.default.post
は、Swiftでアプリ内の異なる部分間でメッセージを送信するための仕組みです。
これは「通知」を送信する機能で、プッシュ通知とは全く別のものです。
簡単に言えば、アプリ内での「お知らせシステム」のようなもので。
ある画面やクラスから別の画面やクラスに対して「○○が起きました」という情報を伝えることができます。
基本的な使い方
NotificationCenterを使うには、「送信側」と「受信側」の2つの設定が必要です。
まるで無線機のように、一方が「送信」し、もう一方が「受信」する仕組みです。
1. 通知を送信する(post)
まずは通知を送信する方法から見てみましょう。
NotificationCenter.default.post
を使って、アプリ内に「○○が起きました」というお知らせを送信できます。
1 2 3 4 5 6 7 8 9 10 11 |
// 基本的な通知の送信 NotificationCenter.default.post(name: Notification.Name("UserLoggedIn"), object: nil) // カスタム通知名を定義して使用 extension Notification.Name { static let userLoggedIn = Notification.Name("UserLoggedIn") static let dataUpdated = Notification.Name("DataUpdated") } NotificationCenter.default.post(name: .userLoggedIn, object: nil) |
ポイント:
- 通知には必ず「名前」をつけます。
- この名前が「どんな種類のお知らせか」を識別するための目印になります。
2. 通知を受信する(観察者として登録)
次に、送信された通知を受信する方法です。
SwiftUIではonReceive
を使って、特定の通知が来るのを「待ち受ける」ことができます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
import SwiftUI struct ContentView: View { @State private var isLoggedIn = false var body: some View { VStack { Text(isLoggedIn ? "ログイン済み" : "ログアウト中") Button("ログイン") { // 通知を送信 NotificationCenter.default.post(name: .userLoggedIn, object: nil) } } .onReceive(NotificationCenter.default.publisher(for: .userLoggedIn)) { _ in // 通知を受信した時の処理 isLoggedIn = true } } } |
ポイント:
onReceive
で特定の通知名を指定して「この通知が来たらこの処理を実行してください」と設定します。- 通知が送信された瞬間に、受信側の処理が自動的に実行されます。
postメソッドのオプション
NotificationCenter.default.post
には以下のパラメータを指定できます:
1. name(必須)
通知の名前を指定します。
この名前で通知を識別します(下記の場合は MyNotification が通知の名前)
1 2 |
NotificationCenter.default.post(name: Notification.Name("MyNotification"), object: nil) |
2. object(オプション)
通知の送信者や関連するオブジェクトを指定します。
「誰がこの通知を送信したのか」を受信側に伝えたい場合に使用します。
1 2 3 4 5 6 7 8 9 |
class UserManager { func login() { NotificationCenter.default.post( name: .userLoggedIn, object: self // 送信者として自分自身を指定 ) } } |
objectを設定することで、複数の画面から同じ通知が送信される可能性がある場合、受信側で「どこから送られてきた通知なのか」を判別できます。
ただし、多くの場合は<code">nilのままで問題ありません。
3. userInfo(オプション)
通知と一緒に追加の情報を送信できます。
辞書形式でデータを渡せるため、「ログインしました」だけでなく「誰がログインしたのか」「いつログインしたのか」といった詳細情報も一緒に送れます。
1 2 3 4 5 6 7 8 9 10 11 |
// データと一緒に通知を送信 NotificationCenter.default.post( name: .dataUpdated, object: nil, userInfo: [ "userId": 12345, "userName": "田中太郎", "timestamp": Date() ] ) |
userInfoは[String: Any]形式の辞書です。
キー(文字列)と値(任意の型)のペアでデータを送信できます。
userInfoを受信する例
受信側では、送信されたuserInfoからデータを取り出して利用できます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
struct ProfileView: View { @State private var userName = "" var body: some View { Text("ユーザー: \(userName)") .onReceive(NotificationCenter.default.publisher(for: .dataUpdated)) { notification in // userInfoからデータを取得 if let userInfo = notification.userInfo, let name = userInfo["userName"] as? String { userName = name } } } } |
コードの解説:
notification.userInfo
- 通知に含まれるuserInfoの辞書を取得userInfo["userName"]
- 辞書から"userName"キーの値を取得as? String
- 取得した値をString型にキャスト(安全にキャスト)
userInfoの値はAny
型なので、使用する前に適切な型(String、Int等)にキャストする必要があります。
実践的な使用例
どんな場面で使うの?
NotificationCenter.default.postは、以下のような「離れた場所にある画面やコンポーネント同士で情報を共有したい」場面で威力を発揮します。
- 商品をカートに追加した時に、画面上部のカートアイコンの数字を更新したい
- ユーザーがログインした時に、複数の画面で表示を変更したい
- 設定画面で変更した内容を、他の画面にも即座に反映させたい
- データの更新があった時に、関連する全ての画面を更新したい
ショッピングカートの例で理解しよう
やりたいこと: ECアプリで、商品詳細画面から「カートに追加」ボタンを押した時に、画面上部のカートアイコンに表示される商品数のバッジを即座に更新したい。
問題: 商品詳細画面(深い階層)とカートアイコン(ナビゲーションバー)は全く別々の場所にあるため、直接的にデータを渡すのが困難。
NotificationCenter.default.postによる解決:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
extension Notification.Name { static let cartUpdated = Notification.Name("CartUpdated") } // 商品をカートに追加する処理(商品詳細画面など) class CartManager: ObservableObject { @Published var itemCount = 0 func addItem() { itemCount += 1 // ここがポイント!カート更新の通知を送信 // アプリ全体に「カートが更新されました」というお知らせを送る NotificationCenter.default.post( name: .cartUpdated, object: nil, userInfo: ["itemCount": itemCount] // 商品数も一緒に送信 ) } } // カートのアイコンを表示するView(ナビゲーションバーなど) struct CartIconView: View { @State private var badgeCount = 0 var body: some View { ZStack { Image(systemName: "cart") if badgeCount > 0 { Text("\(badgeCount)") .foregroundColor(.white) .background(Color.red) .clipShape(Circle()) } } // ここがポイント!カート更新の通知を待ち受け .onReceive(NotificationCenter.default.publisher(for: .cartUpdated)) { notification in // 通知が来たら、送られてきた商品数でバッジを更新 if let userInfo = notification.userInfo, let count = userInfo["itemCount"] as? Int { badgeCount = count } } } } |
どう実現しているか:
- 送信側(CartManager): 商品がカートに追加された瞬間に
NotificationCenter.default.post
でアプリ全体に「カートが更新された」という通知を送信 - 受信側(CartIconView):
onReceive
で常にカート更新の通知を待ち受けており、通知が届いたら即座にバッジの数字を更新 - データの受け渡し:
userInfo
を使って具体的な商品数も一緒に送信するため、受信側は正確な数字を表示できる
この方法により、どんなに離れた場所にあるコンポーネント同士でも、リアルタイムで情報を共有できます。
まとめ
NotificationCenter.default.post
は、アプリ内での効率的な情報共有を可能にする強力な仕組みです。
SwiftUIのonReceive
と組み合わせることで、リアクティブなUIの更新も簡単に実現できるので、ぜひ使ってみてください!