Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I update a Core Data entity from a child view?

I have a Thing Core Data entity with a name field. When I display a [Thing] in a List, I want to be able to edit the name inside the child views. Here's the code that does achieve this, but it feels like poor architecture. A ThingView should really be passed thing, not the thing.name!

Instead, I really want to pass the Thing to ThingView, but if I just did that, then updating thing.name would not cause the view to update because Thing is a reference type. Any thoughts on clean design here?

struct ContentView: View {
  @ObservedObject var observableAllData: ObservableAllData
  var body: some View {
      NavigationView{List(observableAllData.allData.things.indices) { index in
        NavigationLink(destination:ThingView(
          thingName: $observableAllData.allData.things[index].name)) { 
            Text(observableAllData.allData.things[index].name)}
      }
    }
  }
}

struct ThingView: View {
  @Binding var thingName: String
  func updateThing() {
    thingName = "NEW"
  }
  var body: some View {
    VStack{
      Text(thingName)
      Button(action: updateThing) { Text("Update it!")}
    }
  }
}

Edit: Clarification that I want both the ThingView and the ContentView to update when clicking on "Update it".

like image 857
cgold Avatar asked Nov 22 '25 22:11

cgold


1 Answers

You need to pass inside ThingView complete Thing object and use it there instead of its property. Such you will be able update it and save.

So

struct ThingView: View {
  @ObservedObject var thing: Thing

  func updateThing() {
    thing.name = "NEW"
    try? thing.managedObjectContext?.save()
  }
  var body: some View {
    VStack{
      Text(thing.name)
      Button(action: updateThing) { Text("Update it!")}
    }
  }
}

and in link

NavigationLink(destination:ThingView(
  thing: observableAllData.allData.things[index])) { 

Update: pattern is the same everything dependent on CoreData entity put into separated view and make it observed that entity.

In your extended question / what's not very polite ;) / put row into separated view

struct ThingRowView: View {
  @ObservedObject var thing: Thing
   var body: some View {
      NavigationLink(destination:ThingView(thing: thing) { 
            Text(thing.name)}
      }
   }
}

and call it

  NavigationView{List(observableAllData.allData.things.indices) { index in
     ThingRowView(thing: observableAllData.allData.things[index])
  }
like image 94
Asperi Avatar answered Nov 25 '25 19:11

Asperi