Swift 4.1 Decodable 无法使用 nestedContainer 解码嵌套数组
Swift 4.1 Decodable Can't decode nested array with nestedContainer
尝试使用 Codable 编写一个简单的 Swift 4.1
来解析 json
。
我有一个 struct
这样的:
struct GameCharacter : Codable {
var name : String
var weapons : [Weapon]
enum CodingKeys : String, CodingKey {
case name
case weapons
}
init(from decoder: Decoder) {
do {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.name = try container.decode(String.self, forKey: .name)
let weaponsContainer = try container.nestedContainer(keyedBy: Weapon.CodingKeys.self, forKey: .weapons)
self.weapons = try weaponsContainer.decode([Weapon].self, forKey: .weapons)
} catch let error {
print("error: \(error)")
fatalError("error is \(error)")
}
}
}
还有一个像这样:
struct Weapon : Codable {
var name : String
enum CodingKeys : String, CodingKey {
case name
}
init(from decoder: Decoder) {
do {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.name = try container.decode(String.self, forKey: .name)
} catch let error {
print("error: \(error)")
fatalError("error is \(error)")
}
}
}
我也有一个 struct
这样的包装器:
struct Game : Codable {
var characters : [GameCharacter]
enum CodingKeys : String, CodingKey { case characters }
}
json 数据如下所示:
{
"characters" : [{
"name" : "Steve",
"weapons" : [{
"name" : "toothpick"
}]
}]
}
但是,我总是收到类型不匹配错误:
error: typeMismatch(Swift.Dictionary,
Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue:
"characters", intValue: nil), _JSONKey(stringValue: "Index 0",
intValue: 0)], debugDescription: "Expected to decode
Dictionary but found an array instead.", underlyingError:
nil))
这一行:
let weaponsContainer = try container.nestedContainer(keyedBy: Weapon.CodingKeys.self, forKey: .weapons)
我不确定问题出在哪里,因为我显然(在我看来)要求一系列武器,但它认为我正在寻找字典。
想知道是否有人知道我遗漏了什么。
nestedContainers
只有当你想将子字典或子数组解码到父结构中时才需要——例如将 weapons
对象解码到 Game
结构中——事实并非如此,因为您声明了所有嵌套结构。
要解码 JSON 你可以省略所有 CodingKeys 和初始化器,利用 Codable
的魔力,这就足够了:
struct Game : Codable {
let characters : [GameCharacter]
}
struct GameCharacter : Codable {
let name : String
let weapons : [Weapon]
}
struct Weapon : Codable {
let name : String
}
并称之为
do {
let result = try JSONDecoder().decode(Game.self, from: data)
print(result)
} catch { print(error) }
用以下不需要任何自定义初始化程序替换您的结构
import Foundation
struct Weapon: Codable {
let characters: [Character]
}
struct Character: Codable {
let name: String
let weapons: [WeaponElement]
}
struct WeaponElement: Codable {
let name: String
}
并创建
extension Weapon {
init(data: Data) throws {
self = try JSONDecoder().decode(Weapon.self, from: data)
}
现在
let weapon = try Weapon(json)
试试这个
let string = """
{
"characters" : [{
"name" : "Steve",
"weapons" : [{
"name" : "toothpick"
}]
}]
}
"""
struct GameCharacter: Codable {
let characters: [Character]
}
struct Character: Codable {
let name: String
let weapons: [Weapon]
}
struct Weapon: Codable {
let name: String
}
let jsonData = string.data(using: .utf8)!
let decodr = JSONDecoder()
let result = try! decodr.decode(GameCharacter.self, from: jsonData)
let weapon = result.characters.flatMap {[=10=].weapons}
for weaponname in weapon {
print(weaponname.name) //Output toothpick
}
我有同样的问题,JSONDecoder()
只解码了我的 JSON 的第一级,然后我通过从扩展的 class 正文中评论这些方法解决了这个问题来自 Codable
public class Response<T:Codable> : Codable {
public let data : T?
//commented this two function and my problem Solved <3
// enum CodingKeys: String, CodingKey {
// case data
// }
// required public init(from decoder: Decoder) throws {
// data = try T(from: decoder)
// }
}
尝试使用 Codable 编写一个简单的 Swift 4.1
来解析 json
。
我有一个 struct
这样的:
struct GameCharacter : Codable {
var name : String
var weapons : [Weapon]
enum CodingKeys : String, CodingKey {
case name
case weapons
}
init(from decoder: Decoder) {
do {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.name = try container.decode(String.self, forKey: .name)
let weaponsContainer = try container.nestedContainer(keyedBy: Weapon.CodingKeys.self, forKey: .weapons)
self.weapons = try weaponsContainer.decode([Weapon].self, forKey: .weapons)
} catch let error {
print("error: \(error)")
fatalError("error is \(error)")
}
}
}
还有一个像这样:
struct Weapon : Codable {
var name : String
enum CodingKeys : String, CodingKey {
case name
}
init(from decoder: Decoder) {
do {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.name = try container.decode(String.self, forKey: .name)
} catch let error {
print("error: \(error)")
fatalError("error is \(error)")
}
}
}
我也有一个 struct
这样的包装器:
struct Game : Codable {
var characters : [GameCharacter]
enum CodingKeys : String, CodingKey { case characters }
}
json 数据如下所示:
{
"characters" : [{
"name" : "Steve",
"weapons" : [{
"name" : "toothpick"
}]
}]
}
但是,我总是收到类型不匹配错误:
error: typeMismatch(Swift.Dictionary, Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: "characters", intValue: nil), _JSONKey(stringValue: "Index 0", intValue: 0)], debugDescription: "Expected to decode Dictionary but found an array instead.", underlyingError: nil))
这一行:
let weaponsContainer = try container.nestedContainer(keyedBy: Weapon.CodingKeys.self, forKey: .weapons)
我不确定问题出在哪里,因为我显然(在我看来)要求一系列武器,但它认为我正在寻找字典。
想知道是否有人知道我遗漏了什么。
nestedContainers
只有当你想将子字典或子数组解码到父结构中时才需要——例如将 weapons
对象解码到 Game
结构中——事实并非如此,因为您声明了所有嵌套结构。
要解码 JSON 你可以省略所有 CodingKeys 和初始化器,利用 Codable
的魔力,这就足够了:
struct Game : Codable {
let characters : [GameCharacter]
}
struct GameCharacter : Codable {
let name : String
let weapons : [Weapon]
}
struct Weapon : Codable {
let name : String
}
并称之为
do {
let result = try JSONDecoder().decode(Game.self, from: data)
print(result)
} catch { print(error) }
用以下不需要任何自定义初始化程序替换您的结构
import Foundation
struct Weapon: Codable {
let characters: [Character]
}
struct Character: Codable {
let name: String
let weapons: [WeaponElement]
}
struct WeaponElement: Codable {
let name: String
}
并创建
extension Weapon {
init(data: Data) throws {
self = try JSONDecoder().decode(Weapon.self, from: data)
}
现在
let weapon = try Weapon(json)
试试这个
let string = """
{
"characters" : [{
"name" : "Steve",
"weapons" : [{
"name" : "toothpick"
}]
}]
}
"""
struct GameCharacter: Codable {
let characters: [Character]
}
struct Character: Codable {
let name: String
let weapons: [Weapon]
}
struct Weapon: Codable {
let name: String
}
let jsonData = string.data(using: .utf8)!
let decodr = JSONDecoder()
let result = try! decodr.decode(GameCharacter.self, from: jsonData)
let weapon = result.characters.flatMap {[=10=].weapons}
for weaponname in weapon {
print(weaponname.name) //Output toothpick
}
我有同样的问题,JSONDecoder()
只解码了我的 JSON 的第一级,然后我通过从扩展的 class 正文中评论这些方法解决了这个问题来自 Codable
public class Response<T:Codable> : Codable {
public let data : T?
//commented this two function and my problem Solved <3
// enum CodingKeys: String, CodingKey {
// case data
// }
// required public init(from decoder: Decoder) throws {
// data = try T(from: decoder)
// }
}