我想从服务器解析JSON get但我有错误我不知道为什么?!! 这是我的结构:
struct MyResponse:Decodable {
let cats: [Cats]
}
struct Cats: Decodable {
let id: Int
let name: String
let menu: [Cats]
enum CodingKeys:String, CodingKey {
case name
case id
case menu = "SubMenu"
}
}
并创建此扩展程序:
extension MyResponse.Cats {
init(from decoder: Decoder) throws {
let valus = try decoder.container(keyedBy: CodingKeys.self)
name = try valus.decode(String.self, forKey: .name)
id = try valus.decode(Int.self, forKey: .id)
menu = try valus.decodeIfPresent(String.self, forKey: .menu)
}
}
我不知道如何解析这个json。这个json非常重要,因为这是商店的类别。这是我的json值:
{
"cats": [
{
"id": 15,
"name": "کسب و کار ها",
"menu": [
{
"id": 16,
"name": "فروشگاهی",
"menu": [
{
"id": 17,
"name": "ورزشی"
},
{
"id": 18,
"name": "نوشت افزار"
}
]
},
{
"id": 19,
"name": "خدماتی",
"menu": ""
}
]
},
也许在将来的菜单中现在没有子菜单 如果菜单是零或有一些数据怎么处理??
编辑:和init中的这一行:
menu = try valus.decodeIfPresent(String.self, forKey: .menu)
有这个错误:
无法指定类型'字符串的值?'输入' [MyResponse.Cats]'
答案 0 :(得分:1)
键menu
的值可以是
Cat
因此,您需要编写一个处理案例的自定义初始化程序。最简单的方法是解码Cat
数组。如果失败则分配一个空数组。
此外,您需要一个伞形结构用于根对象。
struct Root: Decodable {
let cats : [Cat] // it's recommended to name structs in singular form.
}
struct Cat : Decodable {
let id : Int
let name : String
let menu : [Cat]
enum CodingKeys : String, CodingKey { case name, id, menu }
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
name = try values.decode(String.self, forKey: .name)
id = try values.decode(Int.self, forKey: .id)
do {
menu = try values.decode([Cat].self, forKey: .menu)
} catch {
menu = [Cat]()
}
}
}
或者声明菜单可选
let menu : [Cat]?
如果值不是nil
[Cat]
... } catch { menu = nil }
decodeIfPresent
不起作用,因为该值可以是两种不同的类型。
答案 1 :(得分:0)
只需使[Cats]?
结构符合//: Playground - noun: a place where people can play
import Foundation
struct MyResponse: Codable {
let cats: [Cats]
}
struct Cats: Codable {
let id: Int
let name: String
let menu: [Cats]?
}
// create json mock by encoding
let cats3 = Cats(id: 3, name: "3", menu: nil)
let cats2 = Cats(id: 2, name: "2", menu: nil)
let cats1 = Cats(id: 1, name: "1", menu: [cats2, cats3])
let myResponse = MyResponse(cats: [cats1])
let json = try! JSONEncoder().encode(myResponse)
print(String(bytes: json, encoding: String.Encoding.utf8)) // Optional("{\"cats\":[{\"id\":1,\"name\":\"1\",\"menu\":[{\"id\":2,\"name\":\"2\"},{\"id\":3,\"name\":\"3\"}]}]}")
// create category data by decoding json (your actual question)
do {
let myResponseAgain = try JSONDecoder().decode(MyResponse.self, from: json)
for cats in myResponseAgain.cats {
print(cats.id) // 1
print(cats.name) // 1
print(cats.menu) // Optional([__lldb_expr_30.Cats(id: 2, name: "2", menu: nil), __lldb_expr_30.Cats(id: 3, name: "3", menu: nil)])
print(cats.menu![0].id) // 2
print(cats.menu![0].name) // 2
print(cats.menu![0].menu) // nil
print(cats.menu![1].id) // 3
print(cats.menu![1].name) // 3
print(cats.menu![1].menu) // nil
}
} catch {
print("something went wrong")
}
协议并添加可选数组ValueType="DateTime"
。
FormatString="d"
答案 2 :(得分:0)
JSON示例包含一个表示"menu": ""
的条目,而您的结构假定它是另一个Menu
实例,null
或完全不存在。
正如vadian指出的那样,如果你的子菜单有时会以""
的形式返回,你可以编写一个自定义init(from:)
方法来手动解析JSON,如图所示。但更好的方法是修复生成JSON的任何内容,以便"menu":""
根本不存在,或者如果是,则为"menu":null
(注意,没有引号)。最好在JSON中修复原始问题,而不是编写繁琐的JSON解析init(from:)
来处理问题。
假设您修复了JSON,正如其他人所指出的那样,还存在另一个问题。您的Menu
结构定义了一个名为submenu
的属性,但您的JSON不使用该密钥。它使用menu
。所以,你可以:
更改属性名称:
struct Menu: Codable {
let name: String
let id: Int
let menu: [Menu]?
}
或
使用CodingKeys
枚举:
struct Menu: Codable {
let name: String
let id: Int
let submenu: [Menu]?
enum CodingKeys: String, CodingKey {
case name, id
case submenu = "menu"
}
}
或
将JSON更改为使用submenu
键。
假设您修复了JSON,这表明您可以非常轻松地解析它。这使用方法2,如上所示:
let data = """
{
"cats": [
{
"id": 15,
"name": "کسب و کار ها",
"menu": [
{
"id": 16,
"name": "فروشگاهی",
"menu": [
{
"id": 17,
"name": "ورزشی"
},
{
"id": 18,
"name": "نوشت افزار"
}
]
},
{
"id": 19,
"name": "خدماتی"
}
]
}
]
}
""".data(using: .utf8)!
struct Respons: Codable {
let cats: [Menu]
}
struct Menu: Codable {
let name: String
let id: Int
let submenu: [Menu]?
enum CodingKeys: String, CodingKey {
case name, id
case submenu = "menu"
}
}
do {
let object = try JSONDecoder().decode(Respons.self, from: data)
print(object)
} catch {
print(error)
}