'Use Swift ObservableObject to change view label when UserSettings change

I’ve created a small sample project in Swift Playgrounds to debug an issue I’ve encountered. This sample project contains the a primary ContentView with a single Text field and a button that opens Settings in a modal view.

When I open Settings and change the a setting via a picker, I would like to see the corresponding Text label change in my ContentView. In the current project, I’m using the @ObservableObject Type Alias to track the change, and I see that the setting changes correctly, but the view is not updated. If I restart the preview in Playgrounds, the view is updated with the changed setting. I would expect the Text label to change in real-time.

The code is as follows:

ContentView.swift

import SwiftUI

struct ContentView: View {
    
    @ObservedObject var userSettings = UserSettings()
    
    @State var isModal: Bool = false
    
    var body: some View {
        
        VStack {
            Text("Setting: " + userSettings.pickerSetting)
                .fontWeight(.semibold)
                .font(.title)
            Button(action: {
                    self.isModal = true
                }) {
                    Image(systemName: "gear")
                        .font(.title)
                }
                .padding()
                .foregroundColor(.white)
                .background(Color.gray)
                .cornerRadius(40)
                .sheet(isPresented: $isModal, content: {
                    UserSettingsView()
                })
                .environmentObject(userSettings)
        }
    }
}

UserSettings.swift

import Foundation

class UserSettings: ObservableObject {
    
    @Published var pickerSetting: String {
        didSet {
            UserDefaults.standard.set(pickerSetting, forKey: "pickerSetting")
        }
    }
    
    public var pickerSettings = ["Setting 1", "Setting 2", "Setting 3"]
    
    init() {
        self.pickerSetting = UserDefaults.standard.object(forKey: "pickerSetting") as? String ?? "Setting 1"
    }
}

UserSettingsView.swift

import SwiftUI

struct UserSettingsView: View {
    @ObservedObject var userSettings = UserSettings()
    
    var body: some View {
        NavigationView {
            Form {
                Section(header: Text("")) {
                    Picker(selection: $userSettings.pickerSetting, label: Text("Picker Setting")) {
                        ForEach(userSettings.pickerSettings, id: \.self) { setting in
                            Text(setting)
                        }
                    }
                }
            }
            .navigationBarTitle("Settings")
        }
    }
}


Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source