Hi all!
I have an issue how to handle depending data with live changes via .onReceive action. To show my issue I made a simple example with decimal/hex calculation in Swift Playground on macOS 26:
import SwiftUI
import Combine
@Observable
class AppData {
@Published var baseValue : Int = 0
var intValue: String {
get { String(baseValue) }
set {
guard let v = Int(newValue) else { fatalError("Can't set int!")}
baseValue = v
}
}
var hexValue : String {
get { String(baseValue, radix: 16).uppercased() }
set {
guard let v = Int(newValue, radix: 16) else { fatalError("Can't set hex!")}
baseValue = v
}
}
}
struct ContentView: View {
@State var model = AppData()
var body: some View {
VStack {
HStack {
Text("Decimal Value")
TextField("Decimal Value", text: $model.intValue)
.textFieldStyle(.roundedBorder)
.onReceive(Just(model.intValue)) { newValue in
let allowedCharacters = "0123456789"
let filtered = newValue.filter { allowedCharacters.contains($0) }
if let v = Int(filtered) {
model.baseValue = v
} else {
fatalError("Eeek! (Decimal Value)")
}
}
}
HStack {
Text("Hex Value")
TextField("Hex Value", text: $model.hexValue)
.textFieldStyle(.roundedBorder)
.onReceive(Just(model.hexValue)) { newValue in
let allowedCharacters = "0123456789ABCDEFabcdef"
let filtered = newValue.filter { allowedCharacters.contains($0) }
if let v = Int(filtered, radix: 16) {
model.baseValue = v
} else {
fatalError("Eeek! (Hex Value)")
}
}
}
}
}
}
@main
struct MyApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
Somehow the TextField "Decimal Value" does no longer accept input after the "Hex Value" field was added. What do I miss here?
I got it now working by using no longer calculated properties but an update function. Here is my working code (Swift Playground on macOS 26):
import SwiftUI
import Combine
@Observable
class AppData : ObservableObject {
var baseValue : Int = 0
var intValue : String = "0"
var hexValue : String = "0"
func updateValue(_ v : Int) {
//if self.baseValue == v { return } // no short cut here so that illegal chars are filtered
self.objectWillChange.send()
self.baseValue = v
self.intValue = String(v)
self.hexValue = String(v, radix: 16).uppercased()
}
}
struct ContentView: View {
@State var model = AppData()
var body: some View {
VStack {
Text("Base Value: \(model.baseValue)")
HStack {
Text("Decimal Value")
TextField("Decimal Value", text: $model.intValue)
.textFieldStyle(.roundedBorder)
.onReceive(Just(model.intValue)) { newValue in
let allowedCharacters = "0123456789"
let filtered = newValue.filter { allowedCharacters.contains($0) }
if let v = Int(filtered) {
model.updateValue(v)
}
}
}
HStack {
Text("Hex Value")
TextField("Hex Value", text: $model.hexValue)
.textFieldStyle(.roundedBorder)
.onReceive(Just(model.hexValue)) { newValue in
let allowedCharacters = "0123456789ABCDEFabcdef"
let filtered = newValue.filter { allowedCharacters.contains($0) }
if let v = Int(filtered, radix: 16) {
model.updateValue(v)
}
}
}
}
.padding()
}
}