由于使用JSONDecoder编码器,因此Model数据模型还需要设置遵循可编码性 Codable 协议,才能避免报错。又因为id在JSON文件中不存在,因此需要告诉编译器使用某些CodingKeys,不包括id。如下代码所示:
enum CodingKeys : String, CodingKey { case platformIcon, title, platformName, indexURL }
上述代码中,我们使用枚举类CodingKeys,用来指定Model数据模型中应该接收哪些数据,用于排除请求JSON时缺少ID的问题。另外CodingKey也可以作为关键字替换的方法,当实际开发过程中后端与前端定义的字段名称不一样时,也可是使用该方法进行字段对照映射,这点后面有时间会讲到。
ViewModel模型视图创建完成后,我们来到ContentView视图,要使用ViewModel模型视图链接Model和View,我们需要使用新增一个状态变量,如下代码所示:
@StateObject var viewModel = ViewModel()
声明状态变量viewModel作用是初始化ViewModel并交由SwiftUI进行管理存储,这样我们就可以在View视图中使用ViewModel模式视图中的所有方法和变量。
紧接着,我们将原来在List使用的用@State声明的models数组替换成viewModel中的数组models,如下图所示:
如此,通过URLSession API,我们从网络请求了JSON文件数据,并把它解析到了LIst中并展示出来了。如下图所示:
方法优化:优化“添加身份卡”方法
接下来我们来优化添加身份卡的方法,在ViewModel模型视图中,我们使用@Published声明了数据模型数组models,并在ContentView页面中替换了使用@State声明的models数组。
因此我们可以将所有网络请求、新增、编辑、删除的方法都放在ViewModel模型视图里,然后在所有页面建立链接,新增方法如下代码所示:
// 创建身份卡 func addCard(newItem: Model) { models.append(newItem) }
上述代码中,我们创建了一个方法addCard,通过传入符合Model数据模型格式的常量newItem中,然后将newItem添加到数组models中,完成添加数据的动作。
接下来回到 NewView中,我们引用ViewModel视图模型,并替换原来使用@Binding双向绑定声明的数组models,如下代码所示:
csharp
复制代码
var viewModel:ViewModel
这时候可能会报错,没有关系,这是因为原来@Binding双向绑定声明的数组models建立的关系被破坏掉了,而为什么不像ContentView那样使用@StateObject var viewModel = ViewModel()声明,这是因为在添加页面,添加的数据要加载到ContentView的List列表中,进行数据之间的传递。
添加身份卡的方法需要替换原有的models,换成viewModel视图模型中的addCard方法,如下代码所示:
php
复制代码
self.viewModel.addCard(newItem: newItem)
并且NewView页面预览时,需要赋予变量viewModel值,如下代码所示:
less
复制代码
NewView(viewModel: ViewModel())
上述代码中,我们使用ViewModel视图模型代替纯Model数据模型的数组,并将原来的添加身份卡方法替换为ViewModel创建好的addCard方法,为了预览当前NewView页面,还需要给NewView声明的viewModel变量赋予默认值ViewModel()。
在NewView页面调整后,由于之前我们还在引用NewView视图的相关页面进行了绑定,这时候要回到ContentView视图中,解除之前的绑定,如下图所示:
scss
复制代码
NewView(viewModel: viewModel)
如此,我们便实现了使用Model-View-ViewModel架构模式调整原有项目代码,并实现引用ViewModel视图模型中的方法来创建视图,做到将页面和数据分隔开,使得代码进一步精炼。