I have following problem, please refer to the code below.
In the app I can create an Artist (@Model
) and add some Albums (@Model
) to it. These are stored and displayed as supposed.
When I’m launching the app again and navigating to an Artist to delete for instance an album (using .onDelete(perform: removeAlbum)
in AddAlbumView()
) the new list is passed back to the previews view, but when I’m hitting save
the updated list is not saved to the database.
So the workflow is as follows:
Select an artist -> Add/Show Albums
-> delete an album -> go back -> hit save
The question is: How do I correctly update the list property of my Model (Artist)?
Any help is highly appreciated.
MWE.swift
import SwiftUI
@main
struct MWE_SwiftDataApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}.modelContainer(for: Artist.self)
}
}
ContentView.swift:
import SwiftUI
import SwiftData
struct ContentView: View {
var body: some View {
TabView {
ArtistView()
.tabItem {
Label("All Items", systemImage: "list.bullet")
}
ItemView(artist: nil)
.tabItem {
Label("Add", systemImage: "plus")
}
}
}
}
struct ArtistView: View {
@Query private var artists: [Artist]
@Environment(.modelContext) private var modelContext
var body: some View {
NavigationStack {
List {
ForEach(artists) { artist in
NavigationLink(artist.name) {
ItemView(artist: artist)
}
}
}
.navigationTitle("Artists")
}
}
}
struct ItemView: View {
@Environment(.modelContext) private var modelContext
@State private var name: String = ""
@State private var albums: [Album] = []
let artist: Artist?
var body: some View {
NavigationStack {
Form {
Section("Name") {
TextField("Artist name", text: $name )
}
Section("Albums"){
List {
ForEach(albums, id:.self) { album in
Text(album.name)
}
}
}
Section {
VStack(alignment: .leading) {
NavigationLink("Add/Show Albums", destination: AddAlbumView(artist: name, addedAlbums: $albums))
}
}
}
.onAppear {
if let artist {
name = artist.name
if albums.isEmpty {
albums = artist.album
} else {
albums = albums
}
}
}
.navigationTitle("New Artist")
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
Button {
if let artist {
// New list of albums is not applied
artist.name = name
artist.album = albums
} else {
let newArtist = Artist(name: name, album: albums)
modelContext.insert(newArtist)
name = ""
albums = []
}
} label: {
Text("Save")
}
}
}
}
}
}
struct AddAlbumView: View {
var artist: String
@State private var name: String = ""
@State private var releaseDate: Date = .now
@Binding var addedAlbums: [Album]
var body: some View {
NavigationStack {
VStack(alignment: .leading) {
Text(artist)
.font(.headline)
TextField("Album name", text: $name )
DatePicker(selection: $releaseDate, displayedComponents: [.date]) {
Label("Release Date", systemImage: "calendar")
}
Button(action: {
let newAlbum = Album(name: name, releaseDate: releaseDate)
addedAlbums.append(newAlbum)
name = ""
}, label: {
Text("Add")
.frame(width: 150, height: 40)
.foregroundColor(.white)
.background(name.isEmpty ? Color.gray.opacity(1) : Color.blue.opacity(1))
.cornerRadius(20)
.shadow(radius: 5, y: 8)
})
.disabled(name.isEmpty)
Spacer(minLength: 40)
List {
ForEach(addedAlbums, id: .self) { album in
HStack {
Text(album.name)
Spacer()
Text("Released: (album.releaseDate.formatted(date: .abbreviated, time: .omitted))")
}
}.onDelete(perform: removeAlbum)
}
.padding()
.listStyle(.inset)
}
.padding()
.navigationTitle("Add Album")
}
}
func removeAlbum(index: IndexSet) {
addedAlbums.remove(atOffsets: index)
}
}
@Model
class Artist {
@Attribute(.unique) var name: String
@Relationship(deleteRule: .cascade) var album: [Album]
init(name: String, album: [Album]) {
self.name = name
self.album = album
}
}
@Model
class Album {
var name: String
var releaseDate: Date
init(name: String, releaseDate: Date) {
self.name = name
self.releaseDate = releaseDate
}
}