Swiftui 映射嵌套 JSON 到平面模型

Swiftui Mapping Nested JSON to Flat Model

我需要访问 Memodel 结构的嵌套字典中的数据。来自音乐和图像词典。请需要任何帮助才能正确绘制出来,我已经尝试使用 AzampSharp 的示例 https://www.youtube.com/watch?v=b5wVIQNrI6k,但我相信我做错了什么。谢谢。

import SwiftUI

    struct MemodelAPIResult: Codable {
        let data: [Memodel]
        
        enum CodingKeys: String, CodingKey {
            case data = "results"
        }
    }
    
    
    struct Memodel: Identifiable, Codable {
        var id: String
        var followers: String
        var following: String
        let music: [MemodelMusic]
        let images: [MemodelImages]
        
    }
    
    struct MemodelMusic: Identifiable, Codable, Hashable {
        var id: String
        var musicfile: URL
        var musicname: String
        var musicartistname: String
        var musicgenre: String
    }
    
    struct MemodelImages: Identifiable, Codable, Hashable {
        var id: String
        var albumimages: URL
        var abumlikes: String
        var albumviews: String
    }

下面是我的视图模型中的 ObservableObject

import Foundation
import SwiftUI
import Combine
import CryptoKit

class MeViewmodel: ObservableObject {
    @Published var me: [Memodel]? = nil
    
    
    init() {
            self.fetchme()
    }
    
    func fetchme() {
        
        let url = ""
        
        let session = URLSession(configuration: .default)

        session.dataTask(with: URL(string: url)!) { (data, _, err) in

            if let error = err{
                print(error.localizedDescription)
                return
            }

            guard let APIData = data else {
                print("No Data found")
                return
            }

            do {
                let new = try JSONDecoder().decode(MemodelAPIResult.self, from: APIData)

                DispatchQueue.main.async {
                       self.me = new.data
                }
            }
            catch{
                print(error)
            }
    }
        .resume()
    }
    
}

然后是项目视图

struct MeMusicItemView: View {
    //E-MARK: - Properties
    var me: Memodel
    //E-MARK: - Body
    var body: some View {
            HStack {
                    VStack(alignment: .leading, spacing: 5) {
                        Text(me.music[0].musicname)
                            .font(.callout)
                            .fontWeight(.medium)
                            .foregroundColor(.white)
                        Text(me.music[0].musicartistname)
                            .font(.caption2)
                            .fontWeight(.light)
                            .foregroundColor(.white)
                        
                        Text(me.music[0].musicgenre)
                            .font(.system(size: 8))
                            .fontWeight(.light)
                            .foregroundColor(.gray)
                    }
                }
    }
}

还有父视图中的 ForEach....

if let meMusicData = meMusicData.mememe {
                    ForEach(meMusicData) { music in
                        MeMusicItemView(memusic: music)
                    }
                    } else {
                        ProgressView()
                            .padding(.top, 20)
                    }

没有足够的信息让我真正理解你在做什么,但是 这里有一些代码,您可以根据自己的目的查看和回收:

struct ContentView: View {
    @StateObject var viewModel = MeViewmodel() // <-- here your model
    
    var body: some View {
        List {
            ForEach(viewModel.me) { memod in  // <-- loop over the Memodel array
                ForEach(memod.music) { music in  // <-- loop over the MemodelMusic array
                    MeMusicItemView(memusic: music) // <-- display 1 MemodelMusic
                }
            }
        }
    }
}

struct MeMusicItemView: View {
    //E-MARK: - Properties
    @State var memusic: MemodelMusic // <-- here
    //E-MARK: - Body
    var body: some View {
        HStack {
            VStack(alignment: .leading, spacing: 5) {
                Text(memusic.musicname)
                    .font(.callout)
                    .fontWeight(.medium)
                    .foregroundColor(.pink)
                Text(memusic.musicartistname)
                    .font(.caption2)
                    .fontWeight(.light)
                    .foregroundColor(.green)
                
                Text(memusic.musicgenre)
                    .font(.system(size: 8))
                    .fontWeight(.light)
                    .foregroundColor(.blue)
            }
        }
    }
}

class MeViewmodel: ObservableObject {
    @Published var me: [Memodel] = [] // <--- here no optional, it is easier to deal with

    init() {
        self.fetchme()
    }
    func fetchme() {
        //  ......
    }
}

struct Memodel: Identifiable, Codable {
    var id: String
    var followers: String
    var following: String
    let music: [MemodelMusic]
    let images: [MemodelImages]
}

struct MemodelMusic: Identifiable, Codable, Hashable {
    var id: String
    var musicfile: URL
    var musicname: String
    var musicartistname: String
    var musicgenre: String
}

struct MemodelImages: Identifiable, Codable, Hashable {
    var id: String
    var albumimages: URL
    var abumlikes: String
    var albumviews: String
}