75142913在线留言
【SwiftUI实战】使用Codable协议解码远程json的接口API数据_IOS开发_网络人

【SwiftUI实战】使用Codable协议解码远程json的接口API数据

Kwok 发表于:2021-11-22 22:22:53 点击:1 评论: 0

Codable协议包括了Decoder,Encode这两个协议,我们可以通过定义就能看出来:

typealias Codable = Decodable & Encodable

Codable实现上是Decoder+ Encode的别名而以,所以我们在映射API接口数据的时候使用Codable来定义。

一、获取远程JSON数据结构、解析、显示的流程

关于json网上有太多的说明,这里不再赘述,我们有下面的一个非常简单的一维数组结构来记录网站的:

{
   "id": 1,
   "name": "网络人",
   "url": "http://www.neter8.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.neter8.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.neter8.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)
}
除非注明,网络人的文章均为原创,转载请以链接形式标明本文地址:http://www.neter8.com/ios/179.html
标签:接口CodableKwok最后编辑于:2021-11-23 11:23:22
0
感谢打赏!

《【SwiftUI实战】使用Codable协议解码远程json的接口API数据》的网友评论(0)

本站推荐阅读

热门点击文章