Property wrappers for SwiftUI state

Sofia Martinez Jan 2026
1 tab
import SwiftUI

// MARK: - State and Binding
struct CounterView: View {
    @State private var count = 0

    var body: some View {
        VStack(spacing: 20) {
            Text("Count: \(count)")
                .font(.largeTitle)

            CounterControls(count: $count)
        }
    }
}

struct CounterControls: View {
    @Binding var count: Int

    var body: some View {
        HStack(spacing: 20) {
            Button("-") { count -= 1 }
            Button("+") { count += 1 }
        }
        .buttonStyle(.bordered)
    }
}

// MARK: - ObservableObject and StateObject
class UserSettings: ObservableObject {
    @Published var username = ""
    @Published var isDarkMode = false
    @Published var notificationsEnabled = true

    static let shared = UserSettings()
}

struct SettingsView: View {
    @StateObject private var settings = UserSettings()

    var body: some View {
        Form {
            TextField("Username", text: $settings.username)
            Toggle("Dark Mode", isOn: $settings.isDarkMode)
            Toggle("Notifications", isOn: $settings.notificationsEnabled)
        }
        .environmentObject(settings)
    }
}

// MARK: - Environment and EnvironmentObject
struct ProfileView: View {
    @EnvironmentObject var settings: UserSettings
    @Environment(\.colorScheme) var colorScheme
    @Environment(\.dismiss) var dismiss

    var body: some View {
        VStack {
            Text("Hello, \(settings.username)")
            Text("Current theme: \(colorScheme == .dark ? "Dark" : "Light")")

            Button("Close") {
                dismiss()
            }
        }
    }
}

// MARK: - AppStorage
struct PreferencesView: View {
    @AppStorage("fontSize") private var fontSize = 16.0
    @AppStorage("showImages") private var showImages = true
    @AppStorage("lastLoginDate") private var lastLoginDate = Date()

    var body: some View {
        Form {
            Slider(value: $fontSize, in: 12...24) {
                Text("Font Size: \(Int(fontSize))")
            }

            Toggle("Show Images", isOn: $showImages)

            Text("Last login: \(lastLoginDate.formatted())")
        }
    }
}
1 file · swift Explain with highlit

SwiftUI property wrappers manage state and data flow declaratively. @State creates mutable state owned by a view for simple values. @Binding creates two-way connections to pass state down the hierarchy without ownership. @ObservedObject watches external ObservableObject instances for changes. @StateObject creates and owns ObservableObject instances with proper lifecycle. @EnvironmentObject provides dependency injection across the view tree. @Environment accesses system values like color scheme or size category. @AppStorage persists simple values to UserDefaults. @Published marks properties that trigger view updates. Understanding which wrapper to use prevents memory leaks and ensures correct data flow.