Codable协议包括了Decoder,Encode这两个协议,我们可以通过定义就能看出来:
typealias Codable = Decodable & Encodable
Codable实现上是Decoder+ Encode的别名而以,所以我们在映射API接口数据的时候使用Codable来定义。
关于json网上有太多的说明,这里不再赘述,我们有下面的一个非常简单的一维数组结构来记录网站的:
{
"id": 1,
"name": "网络人",
"url": "http://www.55mx.com"
}
对应解析的结构体为:
struct WebSite: Codable {
let id: Int //ID
let name: String //网站名称
let url: String //网站地址
}
我们使用一个简单的ViewModel来抓取并解析上面的数据:
class WebSiteViewModel: ObservableObject{
@Published private(set) var site = WebSiteModel(id: 0, name: "", url: "")//初始化Model并设置为发布者
init(){
self.fetchData()//当初始化时,自动抓取远程API
}
// ----------------------- 抓取远程API并映射数据的功能 -------------------//
func fetchData(){
URLSession.shared.dataTask(with: URL(string: "http://www.55mx.com/")!) { data, _, _ in
if let data = data{
do{
let response = try JSONDecoder().decode(WebSiteModel.self, from: data) //数据解码
DispatchQueue.main.async {
self.site = response//映射数据(将会自动发布)
}
}catch{
#if DEBUG
print("解析WebSiteModel的JSON出错啦~:",error.localizedDescription)
#endif
}
}
}.resume()
}
}
这样我们就简单的实现获取远程数据的功能,我们可以在视图里这样展示抓取到的内容:
struct WebSiteView: View{
@StateObject var site = WebSiteViewModel()
var body: some View {
VStack{
HStack{
Text("网址:")
Text(site.site.url)
}
HStack{
Text("名称:")
Text(site.site.name)
}
}.id(site.site.id)
}
}
这样我们就实现一整套的数据流程,关于数据流可以通过这里:http://www.55mx.com/ios/114.html
上面我们针对一个一维的数据结构进行了解码操作,哪么面以更为复杂的二维结构我们要怎么解析呢?请看下面的JSON数据:
{
"id": 2,
"name": "美食圈",
"url": "https://www.meishiq.com",
"info":{
"title":"菜谱家常菜做法_菜谱大全",
"logo":"https://static.meishiq.com/logo.gif"
}
}
可以看到info又是一种结构的情况,我们需要下面的结构体来解析:
//解析SiteModel
struct SiteModel: Codable {
let id: Int
let name: String
let url: String
let info: Info
}
//解析Info
struct Info: Codable {
let title: String
let logo: String
}
如果我们不需要对外展示Info,或者不想污染全局的情况可以将Info放到SiteModel这个结构体里做为子结构使用:
struct SiteModel: Codable {
...//同上
let info: Info
//让Info成为SiteModel的子结构
struct Info: Codable { ... }
}
先看下面的数据类型,这是我们在实现开发中最常见的数据返回格式:
{
"code": 200,
"msg": "success",
"cachetime": 864000,
"data": [{
"id": 100123,
"name": "土豆木耳炒鸡蛋",
"url": "https://www.meishiq.com/recipe/100123.html"
},
{
"id": 100131,
"name": "肉丝土豆饼",
"url": "https://www.meishiq.com/recipe/100131.html"
},
{
"id": 100145,
"name": "兰州牛肉拉面汤的配方",
"url": "https://www.meishiq.com/recipe/100145.html"
}]
}
解析Struct如下:
struct RecipeModel: Codable {
let code: Int
let msg: String
let cachetime: Int
let data: [Datum]//注意看这里使用了[]将数据包起来
//子结构
struct Datum: Codable {
let id: Int
let name: String
let url: String
}
}
我们使用[]将数据包起的意思就是可以返回多条相同的数据结构。
有的时候,我们远程没有数据返回,可能不返回,或者返回一个空数据,像这样的情况:
{
"code": 200,
"msg": "success",
"cachetime": 86400,
"data": {
"rid": "100016",
"name": "莲藕炖排骨",
"title": "家常汤品莲藕炖排骨",
"difficulty": "初级入门",
"maketime": "90分钟",
"taste": "家常味",
"major": [
{
"name": "莲藕",
"value": "1 节"
},
{
"name": "肉厚的猪胸骨",
"value": "1 块"
}
],
"minor": []
}
}
其中minor与major这2个的结构是一样的,但它们都可能返回一个空数据,我们针对这个数据进行可空处理的结构体如下:
struct RecipesModel: Codable {
let code: Int
let msg: String
let cachetime: Int
let data: DataClass
//二维数据
struct DataClass: Codable {
let rid, name, title, difficulty: String
let maketime, taste: String
let major, minor: [Major]?//使用Option类型处理返回可空数据
//三维数据
struct Major: Codable {
let name, value: String
}
}
}
这里就基本上包含了在日常开发中遇到的各种数据解析的情况。如果你还有不懂的地方,请留言告诉我哦!
很多时候我们需要使用ForEach或者List遍历数据,它们都要求数据符合Identifiable协议,我们获取到数据没有id也就不能符合该协议,我们就需要使用扩展来实现了:
extension RecipesModel.DataClass:Identifiable{
var id: String{ rid }//使用rid做为Identifiable
}
以上面的数据为例,我们可以使用rid做为Identifiable来识别。
上面为了做简单演示,没有针对错误进行详细的处理工作,在下面被齐解码过程中会经常遇到的一些错误,更方便我们Debug。
do{
let response = try JSONDecoder().decode(JSONModel.self, from: data)
DispatchQueue.main.async {
self.recipe = response.data
}
}catch let DecodingError.dataCorrupted(context) {
print("在解码值时发生的错误。",context)
} catch let DecodingError.keyNotFound(key, context) {
print("健:'\(key)'未找到:", context.debugDescription)
print("编码路径(codingPath):", context.codingPath)
} catch let DecodingError.valueNotFound(value, context) {
print("值:'\(value)'未找到:", context.debugDescription)
print("编码路径(codingPath):", context.codingPath)
} catch let DecodingError.typeMismatch(type, context) {
print("类型:'\(type)'不匹配:", context.debugDescription)
print("编码路径(codingPath):", context.codingPath)
}catch{
print("解析RecipeModel JSON出错啦~:",error.localizedDescription)
}
除非注明,网络人的文章均为原创,转载请以链接形式标明本文地址:https://www.55mx.com/post/179
《【SwiftUI实战】使用Codable协议解码远程json的接口API数据》的网友评论(0)