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")
}
}
}