Ios Swift 4.1可解码罐';使用nestedContainer对嵌套数组进行解码

Ios Swift 4.1可解码罐';使用nestedContainer对嵌套数组进行解码,ios,swift,codable,Ios,Swift,Codable,正在尝试使用Codable编写一个简单的swift4.1来解析json 我有一个类似这样的结构: struct GameCharacter : Codable { var name : String var weapons : [Weapon] enum CodingKeys : String, CodingKey { case name case weapons } init(from decoder: Decoder) { do {

正在尝试使用Codable编写一个简单的
swift4.1
来解析
json

我有一个类似这样的
结构:

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 Game : Codable {
  var characters : [GameCharacter]
  enum CodingKeys : String, CodingKey { case characters }
}
{ 
  "characters" : [{
    "name" : "Steve",
    "weapons" : [{
      "name" : "toothpick"
    }]
  }]
}
还有另一个类似的例子:

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 Game : Codable {
  var characters : [GameCharacter]
  enum CodingKeys : String, CodingKey { case characters }
}
{ 
  "characters" : [{
    "name" : "Steve",
    "weapons" : [{
      "name" : "toothpick"
    }]
  }]
}
我还有一个类似这样的包装器的
结构:

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 Game : Codable {
  var characters : [GameCharacter]
  enum CodingKeys : String, CodingKey { case characters }
}
{ 
  "characters" : [{
    "name" : "Steve",
    "weapons" : [{
      "name" : "toothpick"
    }]
  }]
}
json数据如下所示:

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 Game : Codable {
  var characters : [GameCharacter]
  enum CodingKeys : String, CodingKey { case characters }
}
{ 
  "characters" : [{
    "name" : "Steve",
    "weapons" : [{
      "name" : "toothpick"
    }]
  }]
}
但是,我总是遇到类型不匹配错误:

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 Game : Codable {
  var characters : [GameCharacter]
  enum CodingKeys : String, CodingKey { case characters }
}
{ 
  "characters" : [{
    "name" : "Steve",
    "weapons" : [{
      "name" : "toothpick"
    }]
  }]
}
错误:类型不匹配(Swift.Dictionary, Swift.DecodingError.Context(编码路径:[编码键(stringValue: “字符”,intValue:nil),_JSONKey(stringValue:Index 0), intValue:0)],debugDescription:“需要解码 字典,但找到了数组。“,underlineError: (零)

在这一行:

let weaponsContainer = try container.nestedContainer(keyedBy: Weapon.CodingKeys.self, forKey: .weapons)
我不确定问题是什么,因为我(在我看来)显然是在要求一系列武器,但它认为我无论如何都在寻找一本字典


想知道是否有人知道我遗漏了什么。

nestedContainers
仅当您要将子字典或子数组解码到父结构中时才需要,例如,将
武器
对象解码到
游戏
结构中,但情况并非如此,因为您声明了所有嵌套结构

要解码JSON,您可以省略所有编码键和初始值设定项,利用
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) }

仅当您要将子字典或子数组解码到父结构中时才需要使用
nestedContainers
,例如,将
武器
对象解码到
游戏
结构中,情况并非如此,因为您声明了所有嵌套结构

要解码JSON,您可以省略所有编码键和初始值设定项,利用
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)

将结构替换为以下内容,无需任何自定义初始值设定项

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 {$0.weapons}

for weaponname in weapon {
    print(weaponname.name) //Output toothpick
}
试试这个

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 {$0.weapons}

for weaponname in weapon {
    print(weaponname.name) //Output toothpick
}

我也有同样的问题,
jsondeconder()
只解码我的JSON的第一级,然后我使用从
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)
//    }


}
公共类响应:可编码{
公共数据:T?

//注释了这两个函数并解决了我的问题我也有同样的问题,
jsondeconder()
只解码我的JSON的第一级,然后我用从
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)
//    }


}
公共类响应:可编码{
公共数据:T?

//对这两个函数进行了注释,我的问题得到了解决。感谢@vadian我很早就实现了初始化器,以响应不同的问题。我想我不需要这样做。看起来应该很容易,所以我对增加的复杂度感到恼火,这些复杂度似乎不必要。很高兴它们不是!感谢@vadian I implementted很早就回应了一个不同的问题。我想我不需要这样做。看起来应该很容易,所以我对似乎不必要的额外复杂性感到恼火。很高兴他们没有!