CoreData speichert nicht

Diese Seite verwendet Cookies. Durch die Nutzung unserer Seite erklären Sie sich damit einverstanden, dass wir Cookies setzen. Weitere Informationen

  • CoreData speichert nicht

    Hallo,

    ich tüftele gerade etwas mit CoreData rum und habe mir eine kleine App gebaut. In der App kann ich Bediener anlegen und speichern und die werden auch brav in einer Liste angezeigt, aber wenn ich den selben Bediener editiere scheint CoreData das nicht "auf die Platte" zu speichern. Also ändere ich etwas an einem Bediener und verlasse die Ändern View, dann wir die View die auf dem NaVStack zurück liegt nicht aktualisiert, gehe ich wieder in das ändern rein, sehe ich das was ich geändert habe. Beende ich dann die App und starte Sie erneut sind zwar die Bediener da, aber die Änderungen sind weg.......
    Ich suche nun schon seid 2 Tagen nach dem Problem. Hat hier vielleicht eine Idee

    Das ist die Liste:

    Quellcode

    1. import SwiftUI
    2. struct BedienerList: View {
    3. @StateObject var bedienerVM = BedienerViewModel()
    4. @State var vorname:String = ""
    5. @State var nachname:String = ""
    6. @State var token:String = "0"
    7. @State var showSheet = false
    8. var body: some View {
    9. NavigationStack {
    10. List {
    11. ForEach(bedienerVM.bediener) { bed in
    12. NavigationLink("\(bed.nr) - \(bed.nachname ?? "Error"), \(bed.vorname ?? "Error")") {
    13. BedienerDetail(bediener:bed)
    14. }
    15. .foregroundColor(bed.active ? Color.primary:Color.secondary)
    16. }
    17. .onDelete(perform: bedienerVM.deleteBediener)
    18. }
    19. .navigationTitle("Bediener")
    20. .toolbar {
    21. NavigationLink {
    22. BedienerNeu()
    23. } label: {
    24. VStack {
    25. Image(systemName: "person.fill.badge.plus")
    26. .foregroundColor(Color.primary)
    27. Text("Bediener hinzufügen")
    28. .font(.subheadline)
    29. .foregroundColor(Color.secondary)
    30. }
    31. }
    32. }
    33. }
    34. .onAppear() {
    35. bedienerVM.fetchBediener()
    36. }
    37. }
    38. }
    Alles anzeigen

    Das ist der teil in dem ich dann editiere und es wird nicht gespeichert


    Quellcode

    1. import SwiftUI
    2. struct BedienerDetail: View {
    3. @Environment(\.managedObjectContext) var moc
    4. @ObservedObject var bediener: Bediener
    5. @State private var vorname:String = ""
    6. @State private var nachname:String = ""
    7. @State private var token:String = ""
    8. @State private var nr:Int32 = 0
    9. @State private var active = true
    10. var body: some View {
    11. VStack {
    12. HStack {
    13. List {
    14. Section(header: Text("Bediener ID")) {
    15. TextField("Bediener ID", value: $nr, format: .number)
    16. .disabled(true)
    17. .textFieldStyle(.roundedBorder)
    18. .textInputAutocapitalization(.never)
    19. .multilineTextAlignment(.center)
    20. .font(.largeTitle)
    21. Toggle("Bediener aktiv", isOn: $active)
    22. .onChange(of: active) { newValue in
    23. bediener.active = active
    24. do {
    25. try moc.save()
    26. print("gespeicherte Objekte: \(moc.insertedObjects.count)")
    27. } catch {
    28. print("catch: \(error)")
    29. }
    30. }
    31. }
    32. Section(header: Text("Persönliche Angaben")) {
    33. TextField("Vorname", text: $vorname)
    34. .textFieldStyle(.roundedBorder)
    35. .textInputAutocapitalization(.never)
    36. .font(.largeTitle)
    37. .onChange(of: vorname, perform: { newValue in
    38. bediener.vorname = vorname
    39. })
    40. TextField("Nachname", text: $nachname)
    41. .textFieldStyle(.roundedBorder)
    42. .textInputAutocapitalization(.never)
    43. .font(.largeTitle)
    44. .onChange(of: nachname, perform: { newValue in
    45. bediener.nachname = nachname
    46. })
    47. }
    48. Section(header: Text("Technische Daten")) {
    49. TextField("Token", text: $token)
    50. .textFieldStyle(.roundedBorder)
    51. .textInputAutocapitalization(.never)
    52. .font(.largeTitle)
    53. .onChange(of: token, perform: { newValue in
    54. bediener.token = token
    55. })
    56. }
    57. }
    58. }
    59. }
    60. .onAppear(perform: {
    61. vorname = bediener.vorname ?? "Error"
    62. nachname = bediener.nachname ?? "Error"
    63. token = bediener.token ?? "Error"
    64. nr = bediener.nr
    65. active = bediener.active
    66. })
    67. .onDisappear(perform: {
    68. do {
    69. try moc.save()
    70. print("gespeicherte Objekte: \(moc.insertedObjects.count)")
    71. } catch {
    72. print("catch: \(error)")
    73. }
    74. })
    75. }
    76. }
    Alles anzeigen

    print("gespeicherte Objekte: \(moc.insertedObjects.count)") zeigt "0" an.

    Schon mal danke im voraus.

    Dirk
  • ja, tatsächlich habe ich zum anlegen eine Klasse die das abwickelt:

    Quellcode

    1. import Foundation
    2. import CoreData
    3. class BedienerViewModel: ObservableObject {
    4. private var dataController = DataController(name: "CounterTab")
    5. @Published var bediener:[Bediener] = []
    6. init() {
    7. fetchBediener()
    8. }
    9. func fetchBediener() {
    10. let request = NSFetchRequest<Bediener>(entityName: "Bediener")
    11. request.sortDescriptors = [NSSortDescriptor(key: "nr", ascending: true)]
    12. do {
    13. bediener = try dataController.container.viewContext.fetch(request)
    14. } catch {
    15. print("Error CoreData ")
    16. }
    17. }
    18. func fetchMaxNr()->Int32 {
    19. let request = NSFetchRequest<Bediener>(entityName: "Bediener")
    20. let predicate = NSPredicate(format: "nr==max(nr)")
    21. request.predicate = predicate
    22. do {
    23. bediener = try dataController.container.viewContext.fetch(request)
    24. } catch {
    25. print("Error CoreData ")
    26. }
    27. if bediener.count > 0 {
    28. return bediener[0].nr + 1
    29. } else {
    30. return 1
    31. }
    32. }
    33. func addBediener(vorname:String, nachname:String, token:String, bedienderNr:Int32, bedienerAktiv:Bool) {
    34. let newBediener = Bediener(context: dataController.container.viewContext)
    35. newBediener.id = UUID()
    36. newBediener.vorname = vorname
    37. newBediener.nachname = nachname
    38. newBediener.token = token
    39. newBediener.nr = bedienderNr
    40. newBediener.active = bedienerAktiv
    41. save()
    42. fetchBediener()
    43. }
    44. func deleteBediener(at offsets: IndexSet) {
    45. for offfset in offsets {
    46. let deleteBediener = bediener[offfset]
    47. dataController.container.viewContext.delete(deleteBediener)
    48. }
    49. save()
    50. fetchBediener()
    51. }
    52. func save() {
    53. try? dataController.container.viewContext.save()
    54. }
    55. }
    Alles anzeigen
    Muss ich das "Save()" aus dieser nehmen?

    Grüße

    Dirk
  • Hey,

    ein low hanging fruit ist, folgende Zeile abzuändern:

    Quellcode

    1. try? dataController.container.viewContext.save()
    Mit try? unterdrückst du einen möglichen Error bzw. du erfährst es nicht. Entferne doch mal das ? und catche den etwaigen Error - vielleicht sagt dir CoreData ja bereits ob beim Speichern etwas schief gelaufen ist bzw. was ;)
    Falls hier keine Fehlermeldung kommt, würde ich ebenfalls ein Missgeschick vermuten, wie @MCDan es bereits geschrieben hat.

    Ich kann dir übrigens wärmstens die Mac App "Core Data Lab" empfehlen (bekomme keine Provision ;)) - die nutze ich beim Entwickeln ständig um zu überprüfen, was tatsächlich auf die Platte geschrieben wird.

    LG
  • Erstmal Danke für alle Tips. Leider läufts immer noch nicht.

    Osxer schrieb:

    Hey,

    ein low hanging fruit ist, folgende Zeile abzuändern:

    Quellcode

    1. try? dataController.container.viewContext.save()
    Mit try? unterdrückst du einen möglichen Error bzw. du erfährst es nicht. Entferne doch mal das ? und catche den etwaigen Error - vielleicht sagt dir CoreData ja bereits ob beim Speichern etwas schief gelaufen ist bzw. was ;)
    Falls hier keine Fehlermeldung kommt, würde ich ebenfalls ein Missgeschick vermuten, wie @MCDan es bereits geschrieben hat.

    Ich kann dir übrigens wärmstens die Mac App "Core Data Lab" empfehlen (bekomme keine Provision ;)) - die nutze ich beim Entwickeln ständig um zu überprüfen, was tatsächlich auf die Platte geschrieben wird.

    LG

    Quellcode

    1. func save() {
    2. do {
    3. try dataController.container.viewContext.save()
    4. } catch {
    5. print(error.localizedDescription)
    6. }
    7. }

    Es gibt keinen Fehler wenn diese Funktion ausgeführt wird.

    Grüße

    Dirk
  • Sorry, die ganzen Objekte welche du anführst, sind nicht ersichtlich. Das ist aktuell raten im Raum. Daneben habe ich meine Kristallkugel wegen Unzuverlässigkeit entsorgt. Du musst hier schon mehr Fleisch am Knochen bringen.

    Und Sorry, wir sind hier nicht dein Enticklungsteam das Meilen an Code debuggd um dir weiterzuhelfen. Versuche es kurz und knackig, nachvollziehbar, einzugrenzen, dann kann dir sicher auch geholfen werden.
  • Hallo @Qvex23,

    es ist, wie @Wolf schon angemerkt hat, schwierig, aus den limitierten Code-Snippets schlau zu werden. Viele Fehler finden sich an den Stellen, wo man sie nicht ganz vermutet, was häufig ein zeitintensives Debugger an der völlig falschen Stelle zur Folge hat. Ganz allgemein kann ich dir von der Vorgehensweise zwei Tipps geben:

    - Versuche dein Problem / Bug auf ein absolutes Minimal-Beispiel zu vereinfachen, bei dem der Bug noch reproduzierbar ist. Vereinfache doch vorübergehend dein Bediener Model auf z.B. nur Vorname und Nachname; vereinfache deine Code-Struktur indem du anstelle des FetchController/DataController Konstrukts einfach einen @FetchRequest in der View nutzt, erzeuge auch das Objekt direkt in der View. Wenn dein Problem dann immer noch vorliegt, liegt es womöglich an der Art und Weise wie du den ManagedObjectContext aufsetzt bzw. in die Environment injectest. Wenn es funktioniert, dann kannst du Schritt für Schritt zu deinem aktuellen Code zurückgehen und schauen, wann der Fehler wieder auftritt um ihn so deutlich einzugrenzen.

    - Überprüfe regelmäßig deine Assumptions, um nicht an den falschen Stellen zu suchen. Deine Assumption ist ja etwa "Das Anzeigen der Daten funktioniert korrekt, aber das Abspeichern scheinbar nicht". Aber ist dem wirklich so? Vielleicht funktioniert ja das Abspeichern korrekt und du hast stattdessen beim Anzeigen der Daten einen Bug... ;) Genau aus dem Grund hatte ich dir im letzten Post z.B. die Core Data Lab App empfohlen, sodass du schauen kannst, ob die Daten denn tatsächlich (wie du vermutest) gar nicht erst abgespeichert werden.

    Viele Grüße