I'm building a macOS app where I have an observable Formatter object that uses @AppStorage to store the significant digit settings (see Formatter.swift). The number formatter is passed to the other views as an environment object using the main app struct MyApp.swift. In the preferences window SettingsView.swift, the significant digits are adjusted using steppers. Finally, the number formatter is assigned to text fields in ContentView.swift to format the input.
The problem is the text fields in the content view do not automatically update their format when the significant digits are changed in the settings view. The text labels automatically update because they read the app storage values directly. But the text fields are not observing the change to the number formatter. If I change the settings, restart the app, then the text fields will properly show the updated format. But how do I tell the text field to update when the formatter significant digits change?
Formatter.swift
import Foundation
import SwiftUI
class Formatter: ObservableObject {
@AppStorage("minSigDigits") var minSigDigits = 1
@AppStorage("maxSigDigits") var maxSigDigits = 6
var numberFormatter: NumberFormatter {
let formatter = NumberFormatter()
formatter.numberStyle = .decimal
formatter.usesSignificantDigits = true
formatter.minimumSignificantDigits = self.minSigDigits
formatter.maximumSignificantDigits = self.maxSigDigits
return formatter
}
func resetValues() {
self.minSigDigits = 1
self.maxSigDigits = 6
}
}
MyApp.swift
import SwiftUI
@main
struct MyApp: App {
@StateObject var formatter = Formatter()
var body: some Scene {
WindowGroup {
ContentView().environmentObject(formatter)
}
Settings {
SettingsView().environmentObject(formatter)
}
}
}
ContentView.swift
import SwiftUI
struct ContentView: View {
@State private var min: Double = 0.0
@State private var max: Double = 1.0
@EnvironmentObject var formatter: Formatter
var body: some View {
VStack {
Text("Min Sig. Digits = \(formatter.minSigDigits)")
TextField("enter min value", value: $min, formatter: formatter.numberFormatter)
Text("Max Sig. Digits = \(formatter.maxSigDigits)")
TextField("enter max value", value: $max, formatter: formatter.numberFormatter)
}
.padding()
.frame(width: 400, height: 300)
}
}
SettingsView.swift
import SwiftUI
struct SettingsView: View {
@EnvironmentObject var formatter: Formatter
var body: some View {
VStack {
Stepper("Min Significant Digits: \(formatter.minSigDigits)", value: $formatter.minSigDigits, in: 1...5)
Stepper("Max Significant Digits: \(formatter.maxSigDigits)", value: $formatter.maxSigDigits, in: 6...10)
Button("Reset Values") {
formatter.resetValues()
}
}
.padding()
.frame(width: 300, height: 200)
}
}
