这是我参与8月更文挑战的第11天,活动详情查看:8月更文挑战
一、应用场景
JSON因为其简洁直观的特性,在很多语言中都有广泛的使用,SwiftUI中也不例外。如果只是需要在项目中做一些数据或者配置的简单的初始化,不需要如数据库的增删改查操作的话,使用JSON文件并在项目启动中解析不失为一个好方式。
二、实战
1. 首先在项目Data目录下创建一个文件Test.json,保存有如下数据。
[
{
"id": 1,
"name": "Tom",
"age": 19,
"sex": "男"
},
{
"id": 2,
"name": "Lily",
"age": 22,
"sex": "女"
},
{
"id": 3,
"name": "John",
"age": 17,
"sex": "男"
},
{
"id": 4,
"name": "Lucy",
"age": 28,
"sex": "女"
}
]
2. 然后创建一个struct名字叫Person.swift。
因为后续要从Json解析为Bean,所以要实现Decodable协议。同样,后续要对整个数组进行ForEach遍历,所以实现Identifiable。
代码如下:
struct Person: Identifiable, Decodable {
var id: Int
var name: String
var age: Int
var sex: String
}
3. 最后开始解析JSON。
这里需要分为四步:
-
- 首先,从项目目录中找到
Test.json文件。
- 首先,从项目目录中找到
-
- 将改文件读入
URL中。
- 将改文件读入
-
- 使用
Data解析URL,
- 使用
-
- 最后使用
JSONDecoder解析json数据并将其转换为Person数组。
- 最后使用
class PersonModel: ObservableObject{
@Published var people: [Person] = []
init() {
let pathString = Bundle.main.path(forResource: "Test", ofType: "json")
if let path = pathString {
let url = URL(fileURLWithPath: path)
do{
let data = try Data(contentsOf: url)
let decoder = JSONDecoder()
DispatchQueue.main.async {
do {
self.people = try decoder.decode([Person].self, from: data)
} catch {
print("Decode Json Error")
}
}
}catch{
print("Parse Data Error")
}
}
}
}
pathString是Optional类型,所以要解包。Data解析URL和JSONDecoder解析json有可能抛出错误,所以要用try+do{}catch{}捕获异常。- 这里面用
SwiftUI的combine框架,初始化数据后,在所有的页面中共享次数据 self.people = try decoder.decode([Person].self, from: data)会触发更新视图,知道数据都解析完,才会渲染UI视图,如果数据量特别大的情况下,会出现加载数据时白屏的情况。所以使用DispatchQueue.main.async异步的方式来实现。- 第一步的解析json文件,同样可以通过
HTTP请求,从网络上加载。比如let url = URL(string: "https://xxxxxxxxxxxxxx.com/people")
4. View中加载初始化好的数据
如在ContentView中引用该数据。
struct ContentView: View {
@EnvironmentObject var model: PersonModel
var body: some View {
List{
ForEach(model.people){person in
HStack(spacing: 20){
Text("id:\(person.id)")
Text("name:\(person.name)")
Text("age:\(person.age)")
Text("sex:\(person.sex)")
}
}
}
}
}
效果如下: