SwiftUI 网络问题之如何从 JSON 文件构建模型 The given data was not valid JSON.

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

The given data was not valid 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
}

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

解决方案

使用https://app.quicktype.io/生成 swift 结构,这是使用 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()
    }
}

精品教程推荐


加入我们一起学习SwiftUI

QQ:3365059189
SwiftUI技术交流QQ群:518696470
教程网站:www.openswiftui.com

发表回复