Access an Object and Change Values. up to 2 Class Levels down

Hello together, I hope someone can answer and can give me maybe a little guidance. Is it possible to access and change a child value from a child class in SwiftData? I tried now different ways but couldn't get it to work although I don't get any errors but I am not able to change or set any values.

So the code example below is only a simplified example and I know some minor errors but it is about the principle. Can the Father class access somehow the Children class and for example read the childrenName?

@Model class Father {
var father: String 

var child: Child?
}

@Model class Child {
var childName: String

var child: Children?
var father: Father
}

@Model class Children {
var childrenName: String 

var parent: Child
}

I don't need direct access from the Father to the Children class - it has to go via the child class.

Thanks for any direction or feedback in advance.

Accepted Reply

Here is an example if I understand correctly what you want to achieve.

I have changed some var names to make it clearer for me when coding. I also removed the @Model for this test.

/*@Model*/ class Father {
    var name: String = ""
    var child: Child?
}

/*@Model*/ class Child {
    var name: String = ""
    var grandChild: GrandChild?
    var father: Father = Father()
}

/*@Model*/ class GrandChild {
    var name: String = ""
    var parent: Child = Child()
}

struct ContentView: View {
    
    @State var fatherEd = Father()
    @State var childBob = Child()
    @State var grandChildTom = GrandChild()
    @State var someChange = false   // a trick to force a state change and force redraw ; could be replaced by Observed, but simpler here

    init() {
        grandChildTom.name = "Tom"
        grandChildTom.parent = childBob
        childBob.name = "Bob"
        childBob.grandChild = grandChildTom
        childBob.father = fatherEd
        fatherEd.name = "father Eduard"
        fatherEd.child = childBob
    }
    
    var body: some View {
        VStack {
            Text("Hello")

            Spacer()
                .frame(height: 20)

            if someChange || !someChange {
                Text("father:\(fatherEd.name)")

                Spacer()
                    .frame(height: 20)
                
                if fatherEd.child != nil {
                    Text("child:\(childBob.name)")
                    Text("same as \(fatherEd.child!.name)")
                }
                
                Spacer()
                    .frame(height: 20)
                if fatherEd.child?.grandChild != nil {
                    Text("grandchild:\(grandChildTom.name)")
                    Text("same as \(fatherEd.child!.grandChild!.name)")
                }
                
                Spacer()
                    .frame(height: 20)
            }
            
            Button(action: { // Change the grandChild name through the child
                if someChange {
                    fatherEd.child?.grandChild?.name = "Tom"
                } else {
                    fatherEd.child?.grandChild?.name = "Laureen"
                }
                someChange.toggle() // just to force a change in the state var.
            }) {
                if someChange {
                    Text("Revert grandChild name to Tom")
                } else {
                    Text("Change grandChild name to Laureen")
                }
            }
        }
    }
}

Replies

Here is an example if I understand correctly what you want to achieve.

I have changed some var names to make it clearer for me when coding. I also removed the @Model for this test.

/*@Model*/ class Father {
    var name: String = ""
    var child: Child?
}

/*@Model*/ class Child {
    var name: String = ""
    var grandChild: GrandChild?
    var father: Father = Father()
}

/*@Model*/ class GrandChild {
    var name: String = ""
    var parent: Child = Child()
}

struct ContentView: View {
    
    @State var fatherEd = Father()
    @State var childBob = Child()
    @State var grandChildTom = GrandChild()
    @State var someChange = false   // a trick to force a state change and force redraw ; could be replaced by Observed, but simpler here

    init() {
        grandChildTom.name = "Tom"
        grandChildTom.parent = childBob
        childBob.name = "Bob"
        childBob.grandChild = grandChildTom
        childBob.father = fatherEd
        fatherEd.name = "father Eduard"
        fatherEd.child = childBob
    }
    
    var body: some View {
        VStack {
            Text("Hello")

            Spacer()
                .frame(height: 20)

            if someChange || !someChange {
                Text("father:\(fatherEd.name)")

                Spacer()
                    .frame(height: 20)
                
                if fatherEd.child != nil {
                    Text("child:\(childBob.name)")
                    Text("same as \(fatherEd.child!.name)")
                }
                
                Spacer()
                    .frame(height: 20)
                if fatherEd.child?.grandChild != nil {
                    Text("grandchild:\(grandChildTom.name)")
                    Text("same as \(fatherEd.child!.grandChild!.name)")
                }
                
                Spacer()
                    .frame(height: 20)
            }
            
            Button(action: { // Change the grandChild name through the child
                if someChange {
                    fatherEd.child?.grandChild?.name = "Tom"
                } else {
                    fatherEd.child?.grandChild?.name = "Laureen"
                }
                someChange.toggle() // just to force a change in the state var.
            }) {
                if someChange {
                    Text("Revert grandChild name to Tom")
                } else {
                    Text("Change grandChild name to Laureen")
                }
            }
        }
    }
}

@Claude31 Thank you for your reply. Did you test it? I tried to access the objects the same way as you did but it doesn't work - actually the objects are arrays of objects and I access them through ¢Bindable vars - maybe the issue is here...

I tested the code I posted and it works OK. I could not test your code, missing parts to do so.

actually the objects are arrays of objects and I access them through ¢Bindable vars

Could you post the code showing what those objects are ?

  • I did solve the issue now. Thanks for your directions @Claude31

Add a Comment