@Published: 概要、動作原理、適用方法

著者: IT Sectr 公開日: 2026-06-19 読了時間: 8 分

@Published はCombineフレームワークのproperty wrapperで、ObservableObjectプロトコルに準拠するクラスのプロパティの変更を自動的に公開します。@Publishedでマークされたプロパティの値が変更されると、SwiftUIは objectWillChange を介してシグナルを受信し、そのオブジェクトにサブスクライブしているすべてのビューを再描画します。Apple Combine Framework ドキュメント (2025) によると、@Published は Publisher を生成し、map、filter、debounce などの Combine オペレーターでさらに変換できます。これにより、@Published は MVVM アーキテクチャにおいてデータとユーザーインターフェース間の重要な橋渡し役となります。

重要なポイント

  • @Published — SwiftUIとCombineでObservableObjectプロパティの変更を自動公開するためのproperty wrapper
  • 仕組み: 値が変更されると objectWillChange が呼び出され、サブスクライブされたビューの再描画がトリガーされる
  • Publisher はプロジェクション $property を介してアクセス可能 — ストリームのサブスクライブ、結合、変換が可能
  • ObservedObjectStateObject は自動的に @Published プロパティにサブスクライブする — 手動サブスクリプションは不要
  • iOS 17+ では @Observable マクロが代替手段を提供するが、@Published は Combine パイプラインの標準であり続ける

@Publishedとは?

@Published はCombineモジュールで定義されたproperty wrapperで、クラスのプロパティの変更についてサブスクライバーに自動的に通知する機能を追加します。これはクラス内でのみ(構造体では不可)、ObservableObject プロトコルに準拠するクラスのプロパティにのみ使用できます。

@Published プロパティの値が変更されると、Combine はドル記号プレフィックスを介してアクセス可能な組み込み publisher を通じてイベントを生成します: $propertyName。この publisher は ObservableObjectPublisher であり、ObservableObject 自体に属します。SwiftUI は、ビューが @ObservedObject または @StateObject を使用するときに自動的にこれにサブスクライブし、オブジェクト内の @Published プロパティが変更されるたびにビューを再描画します。

Matt Neuburg の著書 “IOS 18 Programming Fundamentals with Swift” (2025) によると、@Published は willSet パターンの便利なラッパーであり、自動的に objectWillChange.send() を呼び出します。実際には、コンパイラは @Published を willSet オブザーバー付きの computed property に展開するため、手動実装と比較してランタイムオーバーヘッドがゼロになります。

変更がインターフェースに反映される必要があるすべての ObservableObject プロパティに @Published を使用してください。UI に影響しないプロパティについては、@Published のない通常の stored property を使用すると、不要な再描画が減ります。

@Publishedの動作原理

@Published はコンパイル時に 2 つの主要な要素を生成します。1つ目は、新しい値を書き込む前に objectWillChange.send() を呼び出す willSet オブザーバー付きの stored property です。2つ目は、Published.Publisher を返すプロジェクション $propertyName で、Combine パイプラインで直接使用できます。

3 つのプロパティを持つ Settings クラスを考えてみましょう: 2 つの @Published と 1 つの通常のプロパティ:

swift
class Settings: ObservableObject {
    @Published var username: String = "Guest"
    @Published var isDarkMode = false
    var lastLogin: Date = Date()  // without @Published
}

username または isDarkMode が変更されると、SwiftUI は Settings インスタンスにサブスクライブしているすべてのビューを再描画します。lastLogin の変更は再描画をトリガーしません。通常のプロパティの変更についてサブスクライバーに手動で通知する必要がある場合は、willSet オブザーバーで objectWillChange.send() を呼び出すことができます。

重要な詳細: @Published は、プロパティが直接代入された場合にのみ変更を公開します。プロパティが参照型(クラス)であり、参照を置き換えずに内部状態が変更された場合、@Published はそれを検出しません。そのような場合は、手動イベント送信または値型(構造体)への切り替えが必要です。

@PublishedとCombine

@Published は Combine と緊密に統合されています — 各 @Published プロパティは、プロジェクション $propertyName を介してアクセス可能な publisher を自動的に提供します。これにより、フィルタリング、変換、結合、遅延値処理に Combine オペレーターを使用できます。

典型的なシナリオは、デバウンスを使った検索です。入力フィールドは @Published プロパティ searchText にバインドされていますが、サーバーリクエストは 300 ミリ秒の一時停止後にのみ送信する必要があります。$searchText.debounce を使用した Combine は、これを 1 行で解決します:

swift
class SearchViewModel: ObservableObject {
    @Published var searchText = ""
    @Published var results: [String] = []
    private var cancellables = Set<AnyCancellable>()

    init() {
        setupSearchSubscription()
    }

    private func setupSearchSubscription() {
        $searchText
            .debounce(for: .milliseconds(300), scheduler: RunLoop.main)
            .removeDuplicates()
            .sink { [weak self] text in
                self?.performSearch(text)
            }
            .store(in: &cancellables)
    }

    private func performSearch(_ text: String) { }
}

John Sundell の記事 (Swift by Sundell, 2024) によると、@Published と Combine の組み合わせは、SwiftUI アプリケーションにおけるリアクティブパイプラインの標準パターンです: バリデーション、debounce、throttle、combineLatest、他の publisher とのマージ。@Published は命令型 UI コードとリアクティブな Combine の間の橋渡し役として機能します。

@Published vs @Observable マクロ

iOS 17 のリリースに伴い、Apple は @Observable マクロを導入しました。これは ObservableObject と @Published を使わないリアクティビティの代替アプローチを提供します。@Observable は書き込みレベルではなく読み取りレベルでプロパティへのアクセスを自動的に追跡し、より正確な再描画を提供します — 特定の変更されたプロパティを読み取るビューのみが更新されます。

しかし、これは @Published が廃止されたことを意味するわけではありません。@Published は Combine パイプラインの統合が必要な場合に引き続き必要です — プロジェクション $propertyName は @Observable にはない publisher を提供します。さらに、iOS 16 以下との後方互換性のために、@Published+ObservableObject が唯一のオプションです。Apple WWDC 2023 セッション “Discover Observation in SwiftUI” によると、Apple は新しいプロジェクトには @Observable を推奨していますが、既存のコードと Combine シナリオについては @Published のサポートを明示的に維持しています。

実際には、多くのプロジェクトはハイブリッドアプローチを使用しています: 新しいデータモデルは @Observable を使用し、@Published を持つ既存の ObservableObject はリファクタリングせずに残します。@Published は、公開の細かい制御が必要な場合にも不可欠です — たとえば、複数のプロパティのバッチ更新が完了するまで通知を遅延させる場合などです。

@Publishedのよくある間違い

最初の間違いは 構造体で @Published を使用する ことです。コンパイラはエラーを発行します: “Property wrapper cannot be applied to a computed property” または “‘@Published’ is only available on members of a class.” ObservableObjectPublisher は各インスタンスで一意でなければならないクラスであるため、@Published には参照セマンティクスが必要です。

2 番目の間違いは、参照を置き換えずに参照プロパティの内容を変更する ことです。@Published プロパティが配列型 [String] で、array.append("new") を呼び出した場合、配列への参照が変更されていないため、@Published は変更を検出しません。解決策: プロパティに新しい値を代入する array = array + ["new"] か、手動で objectWillChange.send() を使用します。

3 番目の間違いは @Published プロパティの過剰な数 です。各 @Published プロパティは、そのプロパティを読み取るビューだけでなく、ObservableObject にサブスクライブしているすべてのビューの再描画をトリガーします。Point-Free (2025) によると、1 つの大きな ObservableObject を @StateObject と @EnvironmentObject を持つ複数の小さな ObservableObject に分割すると、不要な再描画が減り、パフォーマンスが向上します。

コード例

最初の例は、バリデーション付きの 登録フォーム ViewModel です。@Published プロパティ emailpassword は、Combine パイプラインを介してバリデーションエラーの表示をトリガーします:

swift
class RegistrationViewModel: ObservableObject {
    @Published var email = ""
    @Published var password = ""
    @Published var emailError: String?
    @Published var isFormValid = false
    private var cancellables = Set<AnyCancellable>()

    init() {
        $email
            .map { $0.contains("@") ? nil : "Invalid email" }
            .assign(to: &$emailError)
            .store(in: &cancellables)

        $email.combineLatest($password)
            .map { !$0.isEmpty && !$1.isEmpty }
            .assign(to: &$isFormValid)
            .store(in: &cancellables)
    }
}

2 番目の例は、参照要素のコレクションに対する 手動公開 です。要素内の変更のたびに配列全体を置き換える代わりに、objectWillChange.send() が使用されます:

swift
class TodoItem {
    var title: String
    var isDone = false
    init(title: String) { self.title = title }
}

class TodoListViewModel: ObservableObject {
    @Published var items: [TodoItem] = []

    func toggle(item: TodoItem) {
        item.isDone.toggle()
        self.objectWillChange.send()  // manual notification
    }
}

3 番目の例は、Combine を介した @Published プロパティへの Assign です。Swift 5.9 の新しい構文を使用すると、Optional ラッパーなしでプロジェクション assign(to: &$property) を介して直接代入できます。これは、サブスクリプションを作成せずに publisher を @Published プロパティに接続する最も短い方法です。

よくある質問

@Published を構造体で使用できますか?

いいえ、@Published は ObservableObject に準拠するクラス内でのみ使用できます。構造体では、ローカル状態には @State を、iOS 17+ では @Observable マクロと組み合わせて @Bindable を使用してください。構造体で @Published を使用しようとすると、コンパイルエラーが発生します。

@Published は配列や辞書とどのように動作しますか?

正しいアプローチ: 新しい値を全体として代入します (array = array + ["new"])。@Published は参照の置き換えを追跡し、内容の変更は追跡しません。参照型のコレクションの場合は、要素の内部状態を変更した後に手動で objectWillChange.send() を使用します。

@Published と @State の違いは何ですか?

@State は単一のビュー内のローカル状態用に設計されており、値型でのみ動作します。@Published は、@ObservedObject または @EnvironmentObject を介して複数のビューで読み取ることができる ObservableObject プロパティ用です。@State はよりシンプルで、@Published は Combine 統合により強力です。

すべての ObservableObject プロパティに @Published が必要ですか?

変更が UI を更新する必要があるプロパティのみ に必要です。内部計算、キャッシュ、一時フラグ用のプロパティには @Published は不要です — これにより不要な再描画が減ります。@Published を “このプロパティはインターフェースにとって重要です” というシグナルとして使用してください。

@Published は Core Data とどのように動作しますか?

SwiftUI は @FetchRequest@ObservedObject (NSManagedObject 用) を介して Core Data と統合します。ManagedObject はすでに ObservableObject に準拠しているため、@Published は不要です — NSManagedObject が自動的に変更を通知します。@Published は、データ変換のために Core Data と UI の間の ViewModel 層で使用されます。

まとめ

  • @Published — SwiftUI と Combine パイプラインのために ObservableObject プロパティの変更を自動的に公開する Combine の property wrapper
  • 仕組み: willSet オブザーバーが objectWillChange.send() を呼び出し、プロジェクション $property を介して publisher を生成する
  • Combine: @Published は debounce、map、combineLatest などのオペレーター用の publisher を提供する — UI とリアクティブパイプライン間の架け橋
  • @Observable (iOS 17+) — 新しいプロジェクト向けの代替手段だが、@Published は Combine と後方互換性の標準であり続ける
  • 間違い: @Published は構造体で動作しない、参照型の変更を追跡しない、@Published プロパティの過剰は再描画を増加させる
  • ベストプラクティス: UI に影響するプロパティのみを @Published でマークし、大きな ObservableObject を複数の小さなものに分割する
  • Assign: Swift 5.9 の assign(to: &$property) により、publisher を @Published プロパティに直接サブスクライブできる

ターンキー方式のモバイルアプリケーションを開発します

IT Sectrは2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。

プロジェクトについて相談

こちらもお読みください