So I think this is a bug and not be being dumb. In order to try and get to a MVP which demonstrates the problem I've stripped my code right back to the basics.
I have a swift data model which stores a colour, since swiftData doesn't store colour I am storing the colour as the four elements and using a calulcated property to persist it. My model looks like this:
@Model
class PersistantStateManagerStorage {
init() {
}
var defaultColour: Color {
get {
print("getting colour ")
print("it is \(self._$backingData) \(dfblue)");
return Color(red: dfred, green: dfgreen, blue: dfblue, opacity: dfopacity) }
set {
if let components = newValue.cgColor?.components {
dfred = components[0]
dfgreen = components[1]
dfblue = components[2]
dfopacity = components[3]
}
}
}
// color components for this location (colour can't be stored as a colour which is dumb
var dfred: Double = 1.0
var dfblue: Double = 1.0
var dfgreen: Double = 1.0
var dfopacity: Double = 1.0
}
I then have a view with a colour picker and a rectangle, and I create a singleton object of my model when the view appears:
@MainActor
struct ContentView: View {
@Environment(\.modelContext) private var modelContext
@Query private var persistantStores:[PersistantStateManagerStorage]
var body: some View {
HStack {
ForEach(persistantStores) {
s in
VStack {
ColorPicker("Default Colour", selection: Bindable(s).defaultColour, supportsOpacity: false)
}.frame(maxWidth: 250)
ZStack {
Rectangle().fill(s.defaultColour).position(x:100, y:100).frame(width: 200, height: 200).focusable()
}.background(){
Color.black.ignoresSafeArea()
}.frame(width: 500, height: 500)
}
}.onAppear(){
if self.persistantStores.count == 0
{
print ("make")
let store = PersistantStateManagerStorage()
modelContext.insert(store)
try? modelContext.save()
}
}
}
}
I know the logic of this is a little weird, but it's purely to be the simplest way of demonstrating the problem.
Now, for the weirdness.. You run this and make a new document, if you don't click on the rectangle and simply close the document then all is fine. However if you select the rectangle (note that it is focussable) and then close the file (saving or deleting) then the app will crash with the error:
SwiftData/BackingData.swift:124: Fatal error: Unable to get value - no backing Managed Object
However, if I add a state variable for colour to the view, and change the colour picker to not bind directly to my model oject - such as
ColorPicker("Default Colour", selection: $col, supportsOpacity: false).onChange(of: col){
s.defaultColour = col
}.onAppear()
{
col = s.defaultColour
}
Then all seems happy
Any ideas or is this indeed a bug?