如何从 JSON 文件构建模型

Posted

技术标签:

【中文标题】如何从 JSON 文件构建模型【英文标题】:How to build a model from a JSON file 【发布时间】:2021-11-18 04:20:27 【问题描述】:

这是我第一次在 Swift 中使用 JSON,当我尝试使用我的模型解析文件时,出现以下错误:

给定的数据不是有效的 JSON。

我认为问题在于我如何制作模型。

我解析 JSON 的方式:

import SwiftUI

struct EmergencyView: View 
    let emergency: [EmergencyNumberModel]
    init() 
        let url = Bundle.main.url(forResource: "emergency",
                                  withExtension: "json")!
        let data = try! Data(contentsOf: url)
        emergency = try! JSONDecoder().decode([EmergencyNumberModel].self, from: data) //Error
    
    
    var body: some View 
        List(emergency, id: \.id)  emer in
            
            if emer.Country != nil 
                Label(emer.Country, systemImage: "quote.bubble")
                    .font(.headline)
             else
                Text(emer.Country)
            
        
        navigationTitle("Emergency")
    

这是我使用的 JSON 的一部分,“emergency.json”:

[
  
    "Country": 
      "Name": "Afghanistan",
      "ISOCode": "AF",
      "ISONumeric": "4"
    ,
    "Ambulance": 
      "All": [
        "112"
      ]
    ,
    "Fire": 
      "All": [
        "119"
      ]
    ,
    "Police": 
      "All": [
        "119"
      ]
    ,
    "Dispatch": 
      "All": [
        null
      ]
    ,
    "Member_112": false,
    "LocalOnly": true,
    "Notes": false
  ,
 
 .
 .
 .

]

这是我的模型,“EmergencyNumberModel.swift”:

struct EmergencyNumberModel: Codable, Identifiable 
    var id = UUID()
    let Country: String
    let Ambulance: String
    let Fire: String
    let Police: String
    let Dispatch: String

我的模型中是否需要其他变量才能访问内部键或变量的数据类型错误?

【问题讨论】:

“构建”你的模型,将你的 json 复制并粘贴到quicktype.io 它会为你生成你的 swift 模型。请注意,在 View 的 init() 中进行解码不是一个好主意。为此建立一个专门的模型/经理。也不要使用“!”在您的代码中。 关于的好建议。现在,您的 EmergencyNumberModel 与 JSON 不匹配——它需要进行重大更改才能正确解码(您可能应该使用 do/try/catch 来做——而不是 try!)。 app.quicktype.io 将是解决此问题的最快方式。 如果您收到的错误是“给定的数据不是有效的 JSON”。那么问题不在于您的模型(至少,不是直接的问题),而在于您的 JSON。我建议使用像 JSONlint.com 这样的验证器来确保你的 JSON 是好的。 【参考方案1】:

使用https://app.quicktype.io/,生成快速结构, 这是使用 json 数据的一种基本方法:

struct EmergencyView: View 
    @State var emergencies: [EmergencyModel] = []  // <--- here
    
    var body: some View 
        List(emergencies)  emer in
            if emer.country.name.isEmpty 
                Text("no country name")
             else 
                Label(emer.country.name, systemImage: "quote.bubble").font(.headline)
            
        
        .onAppear 
            if let emrgncy = loadData(from: "emergency")   // <--- here
                emergencies = emrgncy
            
        
    
    
    func loadData(from file: String) -> [EmergencyModel]? 
        do 
            if let filePath = Bundle.main.path(forResource: file, ofType: "json") 
                let data = try Data(contentsOf: URL(fileURLWithPath: filePath))
                let results = try JSONDecoder().decode([EmergencyModel].self, from: data)
                return results
            
         catch 
            print("----> error: \(error)") // <-- todo, deal with errors
        
        return nil
    
    


struct EmergencyModel: Identifiable, Codable 
    let id = UUID()  // <--- here
    let country: Country
    let ambulance, fire, police: Ambulance
    let dispatch: Dispatch
    let member112, localOnly, notes: Bool
    
    enum CodingKeys: String, CodingKey 
        case country = "Country"
        case ambulance = "Ambulance"
        case fire = "Fire"
        case police = "Police"
        case dispatch = "Dispatch"
        case member112 = "Member_112"
        case localOnly = "LocalOnly"
        case notes = "Notes"
    


struct Ambulance: Codable 
    let all: [String]
    
    enum CodingKeys: String, CodingKey 
        case all = "All"
    


struct Country: Codable 
    let name, isoCode, isoNumeric: String
    
    enum CodingKeys: String, CodingKey 
        case name = "Name"
        case isoCode = "ISOCode"
        case isoNumeric = "ISONumeric"
    


struct Dispatch: Codable 
    let all: [JSONNull?]
    
    enum CodingKeys: String, CodingKey 
        case all = "All"
    


class JSONNull: Codable, Hashable 
    
    public static func == (lhs: JSONNull, rhs: JSONNull) -> Bool 
        return true
    
    
    func hash(into hasher: inout Hasher) 
       hasher.combine(0)
    
    
    public init() 
    
    public required init(from decoder: Decoder) throws 
        let container = try decoder.singleValueContainer()
        if !container.decodeNil() 
            throw DecodingError.typeMismatch(JSONNull.self, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Wrong type for JSONNull"))
        
    
    
    public func encode(to encoder: Encoder) throws 
        var container = encoder.singleValueContainer()
        try container.encodeNil()
    

【讨论】:

这并不能解决无效json的问题。

以上是关于如何从 JSON 文件构建模型的主要内容,如果未能解决你的问题,请参考以下文章

如何从实体框架中存在数据模型的json中反序列化对象?

如何从本地 JSON 文件解析数据并保存在模型类中并在 tableview 中使用

如何从 json 数据推断 Django 模型?

如何配置 ProGuard 以尊重 Jackson 模型?

在构建期间启用刷新edmx或从数据库更新模型

如何为three.js模型加载器将对象转换为json文件