繁体   English   中英

SwiftUI 如何使用 查看 Model 与嵌套 JSON

[英]SwiftUI How to use View Model with nested JSON

我正在学习 iOS 开发,我正在尝试修改我的应用程序以使用 MVVM model。 下面我粘贴我正在使用的 json 结构。 我可以访问类别,但是当我尝试遍历 Items 时遇到了问题。 我的观点 model 应该是什么样子? 我需要 2 个视图模型,一个用于类别,另一个用于项目吗? 另外如何将 View Model 与 AppStorage 结合使用?

[
    {
        "id": "8DC6D7CB-C8E6-4654-BAFE-E89ED7B0AF94",
        "name": "Category",
        "items": [
            {
                "id": "59B88932-EBDD-4CFE-AE8B-D47358856B93",
                "name": "Item1",
                "isOn": false
            },
            {
                "id": "E124AA01-B66F-42D0-B09C-B248624AD228",
                "name": "Item2",
                "isOn": false
            }
     }
 ]

看法

struct ContentView: View {
    
    @ObservedObject var viewModel = MyModel()
    var body: some View {
        List {
            ForEach(viewModel.items, id: \.self) { id in
                Text(id.name)
                //how to iterate through items?
            }
        }
    }
}

视图模型

class MyModel: ObservableObject {
    
    @Published var items: [ItemsSection] = [ItemsSection]()

    init(){
        loadData()
    }

    func loadData()  {
        guard let url = Bundle.main.url(forResource: "items", withExtension: "json")
        else {
            print("Json file not found")
            return
        }
        let data = try? Data(contentsOf: url)
        let items = try? JSONDecoder().decode([ItemsSection].self, from: data!)
        self.items = items!
    }
    
    
    func getSelectedItemsCount() -> Int{
        var i: Int = 0
        for itemSection in items {
            let filteredItems = itemSection.items.filter { item in
                return item.isOn
            }
            i = i + filteredItems.count
        }
        return i
    }
}

Model:

struct ItemSection: Codable, Identifiable, Hashable  {
    var id: UUID = UUID()
    var name: String
    var items: [Item]
}

struct Item: Codable, Equatable, Identifiable,Hashable  {
    var id: UUID = UUID()
    var name: String
    var isOn: Bool = false
}

要遍历您的items数组,您可以执行以下操作:

struct ContentView: View {
    // This should be @StateObject as this View owns the viewmodel
    @StateObject var viewModel = MyModel()
    
    var body: some View {
        List {
            //ItemSection is Identifiable so no need for `id: \.self` here.
            ForEach(viewModel.sections) { section in
            //Section is a View provided by Apple that can help you laying
            // out your View. You don´t have to, you can use your own
                Section(section.name){
                    ForEach(section.items){ item in
                        Text(item.name)
                    }
                }
            }
        }
    }
}

我已经更改了 Viewmodel 中的命名,因为我认为items var 的命名实际上应该是sections

class MyModel: ObservableObject {
    
    @Published var sections: [ItemsSection] = [ItemsSection]()
    
    init(){
        loadData()
    }
    
    func loadData()  {
        guard let url = Bundle.main.url(forResource: "items", withExtension: "json")
        else {
            print("Json file not found")
            return
        }
        do {
            let data = try Data(contentsOf: url)
            let sections = try JSONDecoder().decode([ItemsSection].self, from: data)
            
            self.sections = sections
        } catch {
            print("failed loading or decoding with error: ", error)
        }
    }
    
    func getSelectedItemsCount() -> Int{
        var i: Int = 0
        for itemSection in sections {
            let filteredItems = itemSection.items.filter { item in
                return item.isOn
            }
            i = i + filteredItems.count
        }
        return i
    }
}

并且从不使用try? 使用正确的do / catch块并打印错误。 这将帮助您在未来更好地发现问题。 例如,您提供的示例 JSON 格式错误。 如果没有正确的do / catch它只会在强制展开时崩溃。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM