概要
9月1日からMIXIのインターンシップ「Dive Into MIXI」のminimo事業部プロダクト開発グループアプリ負債返済チームで働きました!
SwiftUIで状態管理をしていると、@Published
、@StateObject
、@ObservedObject
、をたくさん目にすると思います。でも「どれが Combine?どれが SwiftUI?」「結局どう違うの?」と混乱しがちです。この記事ではそれぞれの役割を整理します。
対象者
- SwiftUI を触り始めて「状態管理ワード」がごちゃごちゃに見える人
- Combine の「発行と購読」という言葉は知っているけど、実際どうSwiftUIと関係するのか曖昧な人
- 業務コードで
assign(to:)
や$error.map { … }
を見かけて「これもCombine?」と思ったことがある人
私について
現在、インターンでiOS開発を行なっています。
個人開発のときは「なんとなく使えていればOK」くらいで済んでいましたが、業務になるとそうはいきません。なぜこのコードを書くのかを明確に説明できなければ、PRレビューの嵐の中で突っ込まれます。
そこで直面したのが、SwiftUIの状態管理まわりのキーワードたち。
-
@Published
と@StateObject / @ObservedObject
は全部Combineなの? -
ObservableObject
って結局何者? -
.assign(to:)
ってCombine?SwiftUI?
最初はフワッとした理解でやり過ごしていましたが、業務で本格的に触る中で「これはちゃんと整理しないとやばい」と痛感しました。
この記事は、その学びをまとめたものです。
Combineとは?
Combine は Apple が提供する汎用的なリアクティブフレームワーク です。
値の変化をイベントとして発行し、それを宣言的に処理する仕組みを提供しています。
- SwiftUI だけでなく、UIKitやCLIアプリでも使えます。
- ただし SwiftUI の状態管理(
@Published
,ObservableObject
など)は内部的に Combine を利用しているため、SwiftUI に触れていると自然に目にすることが多いです。
Combine の流れはシンプルで、
- 値の変化を Publisher(発行者) が発行
- 必要に応じて Operator(演算子) が変換・加工
- Subscriber(購読者) が受け取って処理
となります。
これはCombineなの?
業務でこんなコードに出会いました。実はこれもCombineの書き方です。
$error
.map { $0 != nil ? .failed : .idle }
.receive(on: DispatchQueue.main)
.assign(to: &$viewState)
流れ(Publisher → Operator → Operator → Subscriber)
-
Publisher (
$error
)-
@Published var error
があると、自動でerror
の Publisher($error
)が生成される - 「error が変わったらイベントを発行」
-
-
Operator (
.map { ... }
)- 受け取った
error
を.failed
/.idle
に変換
- 受け取った
-
Subscriber (
.assign(to:)
)- 最終的な値を
viewState
プロパティへ代入(&$viewState
は@Published 付きプロパティへ書き込む)
- 最終的な値を
図にするとこんな感じです。
用語集
これがCombine?じゃあ、@Published / @StateObject / @ObservedObject は何?となったので、表にまとめました。
仕組み / 記法 | レイヤー | 何をする? | 補足 |
---|---|---|---|
@MainActor / actor / async ・await
|
Swift 言語 / Concurrency | スレッド安全・並行処理を言語レベルで保証 | Combine / SwiftUI とは独立した基盤 |
Publisher / Subscriber / @Published / PassthroughSubject / .sink
|
Combine | 値のストリームを宣言的に処理 | UI不要で利用可能。SwiftUI(〜iOS16) 内部でも利用 |
ObservableObject + @Published / @StateObject / @ObservedObject / @EnvironmentObject
|
SwiftUI (〜iOS16) | 値変化を監視し、Viewを再描画 |
@Published はCombine。SwiftUIがそれを購読してUI更新 |
@Observable / @State
|
SwiftUI (iOS17〜) | フィールドアクセスを自動トラッキングしてViewを再描画 | Combine不要。Swift 5.9+ / iOS 17+ |
なんで Combine 記事なのに @StateObject / @ObservedObject が出てこないことがあるの?
-
純粋に Combine を説明している記事は、UI(SwiftUI)を絡めないので
@StateObject
/@ObservedObject
は登場しません - 代わりに
PassthroughSubject
,.map
,.filter
,.debounce
,.sink
,.assign
など、Publisher/Operator/Subscriber の話が中心になります -
SwiftUI × Combine を説明する記事では、
ObservableObject
と@Published
に加えて@StateObject
/@ObservedObject
が登場します
ここまでの整理
-
@Published は Combine
値の変更をイベントとして発行する仕組み。
→ UI に依存せず、バックグラウンド処理や CLI アプリでも使える -
ObservableObject は SwiftUI への橋渡し
Combine の発行を SwiftUI が監視できるようにするためのプロトコル
→ObservableObject
に準拠しないと、UI の再描画は走らない -
@StateObject / @ObservedObject は SwiftUI の購読手段
-
@StateObject
: View がインスタンスを「所有」して監視する -
@ObservedObject
: 外から渡されたインスタンスを「監視」するだけ
→ どちらも UI 更新専用 の仕組み
-
-
まとめると
-
@Published
: Combine 側の「発行」 -
ObservableObject
: SwiftUI がそれを購読できるようにする「橋」 -
@StateObject / @ObservedObject
: SwiftUI 側での「購読」
-
まとめ
-
Combine は汎用フレームワーク
SwiftUI 専用ではなく、UIKit や CLI アプリでも使える「値の発行と購読の仕組み」。
-
@Published は Combine
値の変化を Publisher として発行する。UI 限定ではなく、バックエンド処理や非UIコードでも利用可能。
-
ObservableObject は橋渡し
Combine の発行を SwiftUI が監視して、View を再描画できるようにするためのプロトコル。
-
@StateObject / @ObservedObject は SwiftUI 専用の購読手段
-
@StateObject
: View がそのオブジェクトを所有するとき -
@ObservedObject
: 外部から渡されたオブジェクトを監視するとき→ Combine の Publisher を SwiftUI が購読して UI を更新している。
-
おわりに
Observationフレームワークの知見を深めたいです。
インターン頑張ります!