Small views can use @State. Larger features often need a separate object that loads data, handles actions, and exposes state to views.
ObservableObject model
This pattern is common in existing SwiftUI apps:
@MainActor
final class ArticleListViewModel: ObservableObject {
@Published private(set) var articles: [Article] = []
@Published private(set) var isLoading = false
private let service: ArticleService
init(service: ArticleService = ArticleService()) {
self.service = service
}
func load() async {
isLoading = true
defer { isLoading = false }
do {
articles = try await service.fetchArticles()
} catch {
articles = []
}
}
}
@Published tells SwiftUI that changes should update dependent views.
@StateObject
Use @StateObject when a view creates and owns an observable object:
struct ArticleListView: View {
@StateObject private var viewModel = ArticleListViewModel()
var body: some View {
List(viewModel.articles) { article in
Text(article.title)
}
.task {
await viewModel.load()
}
}
}
SwiftUI creates the object once for that view identity.
@ObservedObject
Use @ObservedObject when a parent passes an existing observable object into a child:
struct ArticleToolbar: View {
@ObservedObject var viewModel: ArticleListViewModel
var body: some View {
Button("Refresh") {
Task { await viewModel.load() }
}
}
}
The child observes but does not own the object.
Modern Observation
On modern Apple platforms, Swift also has Observation:
import Observation
@Observable
final class ArticleStore {
var articles: [Article] = []
}
Observation can work with SwiftUI state primitives such as @State. You will still see ObservableObject, @Published, @StateObject, and @ObservedObject in many real projects, especially when supporting older OS versions.
Data flow
Prefer one-way data flow:
- state lives in one owner
- views render from state
- user actions call methods
- methods update state
- SwiftUI re-renders affected views
This makes bugs easier to trace.
What to carry forward
- use observable objects for feature-level state
@StateObjectcreates and owns anObservableObject@ObservedObjectobserves an object owned elsewhere@Observableis the newer Observation model on modern platforms- keep UI state updates on
@MainActor - one-way data flow keeps SwiftUI apps understandable
Next, you will build navigation, lists, and reusable components.