SwiftUI JSON-Daten in Array übernehmen

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

  • SwiftUI JSON-Daten in Array übernehmen

    Hallo zusammen,

    Ich bin neu im Forum und eben so neu (Anfänger) in SwiftUI. Ich möchte eine Rezepte-App erstellen und habe nun folgendes programmiert.

    Programmcode für den DataManager:

    import Foundation

    class DataManager {
    func fetchData(completion: @escaping ([Rezepte]) -> Void) {
    guard let url = Bundle.main.url(forResource: "MeineRezepte", withExtension: "json") else {
    print("Keine JSAN-Datei gefunden.")
    completion([])
    return
    }
    URLSession.shared.dataTask(with: url) { rezepte, _, error in
    if let error = error {
    print("Konnte Daten nicht übertragen: \(error.localizedDescription)")
    completion([])
    return
    }
    guard let jsonData = rezepte else {
    print("Keine Daten gefunden.")
    completion([])
    return
    }
    do {
    _ = try JSONDecoder().decode([Rezepte].self, from: jsonData)
    } catch let DecodingError.dataCorrupted(context) {
    print(context)
    } catch let DecodingError.keyNotFound(key, context) {
    print("Schlüssel '\(key)' nicht gefunden:", context.debugDescription)
    print("kodierter Pfad:", context.codingPath)
    } catch let DecodingError.valueNotFound(value, context) {
    print("Wert '\(value)' nicht gefunden:", context.debugDescription)
    print("kodierter Pfad:", context.codingPath)
    } catch let DecodingError.typeMismatch(type, context) {
    print("Typ '\(type)' stimmt nicht:", context.debugDescription)
    print("kodierter Pfad:", context.codingPath)
    } catch {
    print("Fehler: ", error)
    }
    }
    .resume()
    }
    }

    Programmcode für die ContentView:

    import SwiftUI

    struct Rezepte: Codable, Identifiable{
    var id: Int
    let Seite: String
    let Buch: String
    let Rezept: String
    let Kategorie: String
    }

    struct ContentView: View {
    @State private var rezepte = [Rezepte]()
    private let dataManager = DataManager()
    var body: some View {
    NavigationView {
    ScrollView {
    VStack {
    List(rezepte, id: \.id) { item in
    ForEach(rezepte) { rezept in
    HStack {
    Text(String(rezept.id))
    Text(rezept.Seite)
    Text(rezept.Buch)
    Text(rezept.Rezept)
    Text(rezept.Kategorie)
    }
    }

    }
    .onAppear {
    dataManager.fetchData { fetchedData in
    rezepte = fetchedData
    }
    }
    }
    }
    }
    }
    }

    struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
    ContentView()
    }
    }

    #Preview {
    ContentView()
    }

    Leider erscheint im Simulator keine Anzeige der Daten. Wer kann mir behilflich sein? ?(

    Liebe Grüsse

    Marios
  • Hi!

    Willkommen im Forum :)

    Ich werde Dir leider bei SwiftUI nicht weiterhelfen können. Allerdings fällt es auch anderen leichter, wenn Du Quellcode über die entsprechende Schaltfläche der Editor-Werkzeugleiste formatierst: Sonst lassen sich Einrückungen etc. kaum erkennen. Nur als gut gemeinter Tipp...

    Mattes
    Diese Seite bleibt aus technischen Gründen unbedruckt.
  • Hallo Mattes

    Besten Dank für deinen Tipp! Werde das Beispiel nochmals formatiert einstellen:


    Quellcode

    1. import Foundation
    2. class DataManager {
    3. func fetchData(completion: @escaping ([Rezepte]) -> Void) {
    4. guard let url = Bundle.main.url(forResource: "MeineRezepte", withExtension: "json") else {
    5. print("Keine JSAN-Datei gefunden.")
    6. completion([])
    7. return
    8. }
    9. URLSession.shared.dataTask(with: url) { rezepte, _, error in
    10. if let error = error {
    11. print("Konnte Daten nicht übertragen: \(error.localizedDescription)")
    12. completion([])
    13. return
    14. }
    15. guard let jsonData = rezepte else {
    16. print("Keine Daten gefunden.")
    17. completion([])
    18. return
    19. }
    20. do {
    21. _ = try JSONDecoder().decode([Rezepte].self, from: jsonData)
    22. } catch let DecodingError.dataCorrupted(context) {
    23. print(context)
    24. } catch let DecodingError.keyNotFound(key, context) {
    25. print("Schlüssel '\(key)' nicht gefunden:", context.debugDescription)
    26. print("kodierter Pfad:", context.codingPath)
    27. } catch let DecodingError.valueNotFound(value, context) {
    28. print("Wert '\(value)' nicht gefunden:", context.debugDescription)
    29. print("kodierter Pfad:", context.codingPath)
    30. } catch let DecodingError.typeMismatch(type, context) {
    31. print("Typ '\(type)' stimmt nicht:", context.debugDescription)
    32. print("kodierter Pfad:", context.codingPath)
    33. } catch {
    34. print("Fehler: ", error)
    35. }
    36. }
    37. }
    38. }
    39. import SwiftUI
    40. struct Rezepte: Codable, Identifiable{
    41. var id: Int
    42. let Seite: String
    43. let Buch: String
    44. let Rezept: String
    45. let Kategorie: String
    46. }
    47. struct ContentView: View {
    48. @State private var rezepte = [Rezepte]()
    49. private let dataManager = DataManager()
    50. var body: some View {
    51. NavigationView {
    52. ScrollView {
    53. VStack {
    54. List(rezepte, id: \.id) { item in
    55. ForEach(rezepte) { rezept in
    56. HStack {
    57. Text(String(rezept.id))
    58. Text(rezept.Seite)
    59. Text(rezept.Buch)
    60. Text(rezept.Rezept)
    61. Text(rezept.Kategorie)
    62. }
    63. }
    64. }
    65. .onAppear {
    66. dataManager.fetchData { fetchedData in
    67. rezepte = fetchedData
    68. }
    69. }
    70. }
    71. }
    72. }
    73. }
    74. }
    75. struct ContentView_Previews: PreviewProvider {
    76. static var previews: some View {
    77. ContentView()
    78. }
    79. }
    80. #Preview {
    81. ContentView()
    82. }
    Alles anzeigen
    Danke zum Voraus für einen Tipp :saint:
  • Hallo zusammen

    Habe die App nochmals neu programmiert. Leider bekomme ich wieder keine Liste in der DetailView angezeigt. Wer kann mir helfen?
    Die JSON-Datei "Meine_Rezepte.json" habe ich in der Projektstruktur hinterlegt. Sie ist validiert und entspricht der Struktur des Arrays [Rezept].
    Danke zum Voraus für eure Hilfe.

    Quellcode

    1. import SwiftUI
    2. struct ContentView: View {
    3. var body: some View {
    4. ZStack {
    5. Rectangle()
    6. .foregroundColor(.gray)
    7. .edgesIgnoringSafeArea(.all)
    8. NavigationView {
    9. VStack {
    10. Text("Meine Rezepte")
    11. .font(.largeTitle)
    12. .bold()
    13. .foregroundColor(.blue)
    14. Image(systemName: "cooktop.fill")
    15. .resizable()
    16. .font(.largeTitle)
    17. .foregroundColor(.blue)
    18. .padding()
    19. List {
    20. NavigationLink(destination: DetailView()) {
    21. Text("Gehe zur Rezepte-Liste")
    22. .font(.title)
    23. .bold()
    24. .foregroundColor(.red)
    25. }
    26. }
    27. }
    28. }
    29. }
    30. }
    31. }
    32. struct ContentView_Previews: PreviewProvider {
    33. static var previews: some View {
    34. ContentView()
    35. }
    36. }
    37. import SwiftUI
    38. struct DetailView: View {
    39. @State private var rezepte = [Rezept]()
    40. var body: some View {
    41. Text("Rezepte-Liste")
    42. .font(.largeTitle)
    43. .bold()
    44. .foregroundColor(.blue)
    45. ScrollView {
    46. List {
    47. VStack(alignment: .leading) {
    48. ForEach(rezepte, id: \.id) { rezept in
    49. HStack {
    50. Text(rezept.id)
    51. Text(rezept.Seite)
    52. Text(rezept.Buch)
    53. Text(rezept.Rezept)
    54. Text(rezept.Kategorie)
    55. }
    56. }
    57. }
    58. .padding(6)
    59. }
    60. }
    61. .onAppear(perform: { rezepte = decode("Meine_Rezepte.json")})
    62. }
    63. }
    64. struct DetailView_Previews: PreviewProvider {
    65. static var previews: some View {
    66. DetailView()
    67. }
    68. }
    69. import SwiftUI
    70. struct Rezept: Codable {
    71. var id: String
    72. var Seite: String
    73. var Buch: String
    74. var Rezept: String
    75. var Kategorie: String
    76. }
    77. func decode(_ file: String) -> [Rezept] {
    78. guard let url = Bundle.main.url(forResource: file, withExtension: nil) else {
    79. fatalError("Konnte die JSON-Datei \(file) im Bundle nicht finden.")
    80. }
    81. guard let data = try? Data(contentsOf: url) else {
    82. fatalError("Konnte die JSON-Datei \(file) nicht aus dem Bundle laden.")
    83. }
    84. let decoder = JSONDecoder()
    85. guard let loadedFile = try? decoder.decode([Rezept].self, from: data) else {
    86. fatalError("Konnte die JSON-Datei \(file) nicht decodieren.")
    87. }
    88. return loadedFile
    89. }
    Alles anzeigen
  • Eine List hat bereits ein entsprechendes Design und bringt einige Funktionalitäten wie die ScrollView bereits mit.
    Da also jede Liste eine ScrollView hat, die Liste aber in einer ScrollView ist, hast du hier quasi eine ScrollView welche in einer ScrollView steckt. Dies führt zu einem Konflikt.
    Du solltest dich daher entscheiden, ob du die Liste streichst und dich selbst um alles (wie z.B. um die ScrollView.) kümmerst oder ob du die Liste nimmst (dann wäre, in meinen Augen, auch der VStack unnötig).

    Also ohne Liste:

    Quellcode

    1. ScrollView {
    2. VStack(alignment: .leading) {
    3. ForEach(rezepte, id: \.id) { rezept in
    4. HStack {
    5. Text(rezept.id)
    6. Text(rezept.Seite)
    7. Text(rezept.Buch)
    8. Text(rezept.Rezept)
    9. Text(rezept.Kategorie)
    10. }
    11. }
    12. }
    13. .padding(6)
    14. }
    Alles anzeigen

    Oder Mit Liste

    Quellcode

    1. List {
    2. ForEach(rezepte, id: \.id) { rezept in
    3. HStack {
    4. Text(rezept.id)
    5. Text(rezept.Seite)
    6. Text(rezept.Buch)
    7. Text(rezept.Rezept)
    8. Text(rezept.Kategorie)
    9. }
    10. }
    11. .padding(6)
    12. }
    Alles anzeigen
    Oder sogar noch etwas kompakter mit List:

    Quellcode

    1. List (rezepte, id: \.id) { rezept in
    2. HStack {
    3. Text(rezept.id)
    4. Text(rezept.Seite)
    5. Text(rezept.Buch)
    6. Text(rezept.Rezept)
    7. Text(rezept.Kategorie)
    8. }
    9. .padding(6)
    10. }

    Du solltest außerdem darauf achten mit möglichst aktuellen Quellen zu lernen. NavigationView ist deprecated, heißt es wird nicht mehr verwendet, nimm stattdessen NavigationStack.

    Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von Rumpelstiltskin ()