I have a problem with SwiftData and inserting child records. The insert itself works but the views are not updated. If I add a new court
record in DetailView
, tournament.title
in ContentView
changes to Tournament with new court but tournament.courts.count
is still 1
and not 2
, 3
, … Also the List
in DetailView
shows only the initial court and not the new added.
The ist only a view problem. If I start the app again, it looks fine and all added courts are shown.
Any idea how I can refresh the view after adding or changing child records?
This is like my models and code looks like:
Tournament model:
@Model
final class Tournament {
var title: String
@Relationship(deleteRule: .cascade, inverse: \Court.tournament) var courts: [Court]
init(title: String, courts: [Court] = []) {
self.title = title
self.courts = courts
}
}
Court model:
@Model
final class Court {
@Relationship var tournament: Tournament
var number: Int
init(tournament: Tournament, number: Int) {
self.tournament = tournament
self.number = number
}
}
ContentView:
struct ContentView: View {
@Environment(\.modelContext) private var modelContext
@Query var tournaments: [Tournament]
@State var selectedTournament: Tournament?
var body: some View {
NavigationSplitView {
List(selection: $selectedTournament) {
ForEach(tournaments) { tournament in
NavigationLink(value: tournament) {
HStack {
Text("\(tournament.title)")
Spacer()
Text("(\(tournament.courts.count))")
}
}
}
}
.toolbar {
ToolbarItem {
Button(action: {
addTournament()
}) {
Label("Add tournament", systemImage: "plus")
}
}
}
} detail: {
DetailView(tournament: selectedTournament)
}
}
private func addTournament() {
let newTournament = Tournament(title: "New tournament")
modelContext.insert(newTournament)
let court = Court(tournament: newTournament, number: 1)
modelContext.insert(court)
try? modelContext.save()
}
}
DetailView:
struct DetailView: View {
@Environment(\.modelContext) private var modelContext
var tournament: Tournament?
var body: some View {
if let tournament {
List {
Section(tournament.title) {
ForEach(tournament.courts) { court in
Text("\(court.number)")
}
}
}
Button {
addCourt()
} label: {
Text("Add court")
}
} else {
emptyView // ContentUnavailableView
}
}
func addCourt() {
if let tournament {
let newCourt = Court(tournament: tournament, number: tournament.courts.count+1)
modelContext.insert(newCourt)
tournament.title = "Tournament with new court"
try? modelContext.save()
}
}
}
Update
I found a solution but I don’t know why this works. If I change both relations to optional, the views will be refreshed on adding records.
@Model
final class Tournament {
var title: String
@Relationship(deleteRule: .cascade, inverse: \Court.tournament) var courts: [Court]?
…
}
@Model
final class Court {
var tournament: Tournament?
…
The problem is solved with defining the tournament
property in Court
as optional.
@Model
final class Court {
var tournament: Tournament?
…