[英]SwiftUI How to use View Model with nested JSON
I'm learning iOS development and I'm trying to modify my app to use MVVM model.我正在学习 iOS 开发,我正在尝试修改我的应用程序以使用 MVVM model。 Below I'm pasting json structure that I'm using.
下面我粘贴我正在使用的 json 结构。 I'm able to access categories, but I encountered an issue when I tried to iterate through Items.
我可以访问类别,但是当我尝试遍历 Items 时遇到了问题。 How my view model should look like?
我的观点 model 应该是什么样子? Do I need 2 view models one for Category and another one for Item?
我需要 2 个视图模型,一个用于类别,另一个用于项目吗? Also how to combine View Model with AppStorage?
另外如何将 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
}
}
]
View看法
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?
}
}
}
}
ViewModel视图模型
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: 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
}
To iterate over the your items
array you can do something like this:要遍历您的
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)
}
}
}
}
}
}
I´ve changed the naming in thew Viewmodel as I think the naming of items
var should really be sections
.我已经更改了 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
}
}
And never use try?
并且从不使用
try?
use a proper do / catch
block and print the error.使用正确的
do / catch
块并打印错误。 This will help you in future to identify problems better.这将帮助您在未来更好地发现问题。 For example the example JSON you provided is malformatted.
例如,您提供的示例 JSON 格式错误。 Without proper
do / catch
it will just crash while force unwrap.如果没有正确的
do / catch
它只会在强制展开时崩溃。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.