@Published はCombineフレームワークのproperty wrapperで、ObservableObjectプロトコルに準拠するクラスのプロパティの変更を自動的に公開します。@Publishedでマークされたプロパティの値が変更されると、SwiftUIは objectWillChange を介してシグナルを受信し、そのオブジェクトにサブスクライブしているすべてのビューを再描画します。Apple Combine Framework ドキュメント (2025) によると、@Published は Publisher を生成し、map、filter、debounce などの Combine オペレーターでさらに変換できます。これにより、@Published は MVVM アーキテクチャにおいてデータとユーザーインターフェース間の重要な橋渡し役となります。
重要なポイント
objectWillChange が呼び出され、サブスクライブされたビューの再描画がトリガーされる$property を介してアクセス可能 — ストリームのサブスクライブ、結合、変換が可能@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 はコンパイル時に 2 つの主要な要素を生成します。1つ目は、新しい値を書き込む前に objectWillChange.send() を呼び出す willSet オブザーバー付きの stored property です。2つ目は、Published.Publisher を返すプロジェクション $propertyName で、Combine パイプラインで直接使用できます。
3 つのプロパティを持つ Settings クラスを考えてみましょう: 2 つの @Published と 1 つの通常のプロパティ:
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 プロパティは、プロジェクション $propertyName を介してアクセス可能な publisher を自動的に提供します。これにより、フィルタリング、変換、結合、遅延値処理に Combine オペレーターを使用できます。
典型的なシナリオは、デバウンスを使った検索です。入力フィールドは @Published プロパティ searchText にバインドされていますが、サーバーリクエストは 300 ミリ秒の一時停止後にのみ送信する必要があります。$searchText.debounce を使用した Combine は、これを 1 行で解決します:
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 の間の橋渡し役として機能します。
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 を使用する ことです。コンパイラはエラーを発行します: “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 プロパティ email と password は、Combine パイプラインを介してバリデーションエラーの表示をトリガーします:
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() が使用されます:
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 は ObservableObject に準拠するクラス内でのみ使用できます。構造体では、ローカル状態には @State を、iOS 17+ では @Observable マクロと組み合わせて @Bindable を使用してください。構造体で @Published を使用しようとすると、コンパイルエラーが発生します。
正しいアプローチ: 新しい値を全体として代入します (array = array + ["new"])。@Published は参照の置き換えを追跡し、内容の変更は追跡しません。参照型のコレクションの場合は、要素の内部状態を変更した後に手動で objectWillChange.send() を使用します。
@State は単一のビュー内のローカル状態用に設計されており、値型でのみ動作します。@Published は、@ObservedObject または @EnvironmentObject を介して複数のビューで読み取ることができる ObservableObject プロパティ用です。@State はよりシンプルで、@Published は Combine 統合により強力です。
変更が UI を更新する必要があるプロパティのみ に必要です。内部計算、キャッシュ、一時フラグ用のプロパティには @Published は不要です — これにより不要な再描画が減ります。@Published を “このプロパティはインターフェースにとって重要です” というシグナルとして使用してください。
SwiftUI は @FetchRequest と @ObservedObject (NSManagedObject 用) を介して Core Data と統合します。ManagedObject はすでに ObservableObject に準拠しているため、@Published は不要です — NSManagedObject が自動的に変更を通知します。@Published は、データ変換のために Core Data と UI の間の ViewModel 層で使用されます。
まとめ
objectWillChange.send() を呼び出し、プロジェクション $property を介して publisher を生成するassign(to: &$property) により、publisher を @Published プロパティに直接サブスクライブできるターンキー方式のモバイルアプリケーションを開発します
IT Sectrは2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。