I have a two CoreData objects:
RoadTrip
StatePlate
.Each RoadTrip
items holds an NSSet
of StatePlate
.
Screen 1 (TripList
) shows a list of all RoadTrip
items. Screen 2 (StateList
) shows a list of all StatePlate
items in associated with the RoadTrip
that a user selects. Selecting a StatePlate
item in Screen 2 will toggle a bool value associated with that item.
Even though I can show the data and can toggle the bool value of each StatePlate
, I am not seeing an immediate change to the UI of the screen. The StatePlate
should jump from Section to Section in Screen 2 when it's bool value is toggled.
How can I pass this FetchedObject correctly from Screen 1 to Screen 2 so the UI is binded with the data?
Screen 1 (TripList
)
struct TripList: View {
@Environment(\.managedObjectContext) var managedObjectContext
@FetchRequest(entity: RoadTrip.entity(), sortDescriptors: []) var roadTripItems: FetchedResults<RoadTrip>
var body: some View {
List {
ForEach(roadTripItems, id: \.self) { trip in
NavigationLink(destination: StateList(trip: trip)
.environment(\.managedObjectContext, self.managedObjectContext)) {
TripRow(roadTrip: trip)
}
}
}
}
}
Screen 2 (StateList
)
struct StateList: View {
@Environment(\.managedObjectContext) var managedObjectContext
var trip: RoadTrip
var plates: [StatePlate] {
trip.plateArray
}
var unseenPlates: [StatePlate] {
trip.plateArray.filter { !$0.hasBeenSeen }
}
var seenPlates: [StatePlate] {
trip.plateArray.filter { $0.hasBeenSeen }
}
var body: some View {
List {
if !unseenPlates.isEmpty {
Section(header: Text("Unseen Plates")) {
ForEach(unseenPlates, id: \.self) { plate in
StateRow(plate: plate)
}
}
}
if !seenPlates.isEmpty {
Section(header: Text("Seen Plates")) {
ForEach(seenPlates, id: \.self) { plate in
StateRow(plate: plate)
}
}
}
}
}
}
StateRow
struct StateRow: View {
@Environment(\.managedObjectContext) var managedObjectContext
@ObservedObject var plate: StatePlate
var body: some View {
Button(action: {
self.plate.hasBeenSeen.toggle()
try? self.managedObjectContext.save()
}) {
HStack {
Text(String(describing: plate.name!))
Spacer()
if plate.hasBeenSeen {
Image(systemName: "eye.fill")
} else {
Image(systemName: "")
}
}
}
}
}
Your trip
as object is not changed when plate
has changed, so even if it was observed UI was not refreshed.
Here is possible force-refresh approach.
struct StateList: View {
@Environment(\.managedObjectContext) var managedObjectContext
@ObservedObject var trip: RoadTrip // << make observed
// .. other code
and add handling for updated plate
/s
StateRow(plate: plate)
.onReceive(plate.objectWillChange) { _ in
self.trip.objectWillChange.send()
}