Help us improve
Share bugs, ideas, or general feedback.
From swiftui-dev
Explains SwiftUI data flow with @State, @Binding, @Observable, @Bindable, and environment values. Useful for managing state, bindings, and system values in views.
npx claudepluginhub arustydev/agents --plugin swiftui-devHow this skill is triggered — by the user, by Claude, or both
Slash command
/swiftui-dev:swiftui-data-flowThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Understanding SwiftUI's data flow mechanisms including @Observable, @State, @Binding, and environment values.
Provides SwiftUI patterns for @Observable state management, view composition, NavigationStack navigation, environment injection, and performance optimization in iOS/macOS apps.
Provides SwiftUI patterns for state management (@State/@Binding/@ObservableObject), view composition, Observable protocol, ViewModifiers, and declarative UI in iOS/macOS apps.
Guides SwiftUI app architecture with MV pattern, @Observable state management, view composition, environment wiring, and async loading for iOS 26+.
Share bugs, ideas, or general feedback.
Understanding SwiftUI's data flow mechanisms including @Observable, @State, @Binding, and environment values.
struct CounterView: View {
@State private var count = 0
var body: some View {
VStack {
Text("Count: \(count)")
Button("Increment") {
count += 1
}
}
}
}
struct ToggleRow: View {
let title: String
@Binding var isOn: Bool
var body: some View {
Toggle(title, isOn: $isOn)
}
}
struct SettingsView: View {
@State private var notificationsEnabled = false
var body: some View {
Form {
ToggleRow(title: "Notifications", isOn: $notificationsEnabled)
}
}
}
@Observable
final class UserSettings {
var username = ""
var notificationsEnabled = true
var theme: Theme = .system
// Computed properties work automatically
var isValid: Bool {
!username.isEmpty
}
}
struct SettingsView: View {
@State private var settings = UserSettings()
var body: some View {
Form {
TextField("Username", text: $settings.username)
Toggle("Notifications", isOn: $settings.notificationsEnabled)
Picker("Theme", selection: $settings.theme) {
ForEach(Theme.allCases) { theme in
Text(theme.rawValue).tag(theme)
}
}
}
.disabled(!settings.isValid)
}
}
struct EditUserView: View {
@Bindable var user: User // User is @Observable
var body: some View {
Form {
TextField("Name", text: $user.name)
TextField("Email", text: $user.email)
}
}
}
struct AdaptiveView: View {
@Environment(\.colorScheme) private var colorScheme
@Environment(\.horizontalSizeClass) private var sizeClass
@Environment(\.dismiss) private var dismiss
var body: some View {
VStack {
Text("Theme: \(colorScheme == .dark ? "Dark" : "Light")")
Button("Close") {
dismiss()
}
}
}
}
// Define the key
private struct APIClientKey: EnvironmentKey {
static let defaultValue: APIClient = .live
}
// Extend EnvironmentValues
extension EnvironmentValues {
var apiClient: APIClient {
get { self[APIClientKey.self] }
set { self[APIClientKey.self] = newValue }
}
}
// Usage
struct DataView: View {
@Environment(\.apiClient) private var api
var body: some View {
// Use api
}
}
// Injection
MyApp()
.environment(\.apiClient, .mock)
@Observable
final class AppState {
var currentUser: User?
var isAuthenticated: Bool { currentUser != nil }
}
// In App
@main
struct MyApp: App {
@State private var appState = AppState()
var body: some Scene {
WindowGroup {
ContentView()
.environment(appState)
}
}
}
// In View
struct ProfileView: View {
@Environment(AppState.self) private var appState
var body: some View {
if let user = appState.currentUser {
Text("Hello, \(user.name)")
}
}
}
struct ParentView: View {
@State private var data = [Item]()
var body: some View {
List(data) { item in
ChildRow(item: item) // Pass as value
}
}
}
struct FilterView: View {
@Binding var selectedFilter: Filter
var body: some View {
Picker("Filter", selection: $selectedFilter) {
ForEach(Filter.allCases) { filter in
Text(filter.title).tag(filter)
}
}
}
}
struct ItemRow: View {
let item: Item
let onDelete: () -> Void
var body: some View {
HStack {
Text(item.name)
Spacer()
Button("Delete", action: onDelete)
}
}
}
@Observable
final class ShoppingCart {
var items: [CartItem] = []
var total: Decimal {
items.reduce(0) { $0 + $1.price * Decimal($1.quantity) }
}
func add(_ product: Product) {
if let index = items.firstIndex(where: { $0.productId == product.id }) {
items[index].quantity += 1
} else {
items.append(CartItem(product: product))
}
}
}
// Shared across views via environment
struct ProductView: View {
@Environment(ShoppingCart.self) private var cart
let product: Product
var body: some View {
Button("Add to Cart") {
cart.add(product)
}
}
}
// OLD (pre-iOS 17)
class ViewModel: ObservableObject {
@Published var items: [Item] = []
}
struct MyView: View {
@StateObject private var viewModel = ViewModel()
}
// NEW (iOS 17+)
@Observable
final class ViewModel {
var items: [Item] = []
}
struct MyView: View {
@State private var viewModel = ViewModel()
}