如何解析一个 JSON 数组数组并通过名称引用内部数组的成员?
How to parse a JSON array of arrays and refer to the members of the inner array by names?
在 Swift Playground 中,我尝试解析以下数据:
let jsonMoves:String =
"""
{ "moves":
[
[0, 'CAT (7)', 'ACT'],
[1, 'EXTRA (14)', 'ERXT'],
[0, 'TOP (22)', 'PO'],
[1, 'TOY (9)', 'Y']
]
}
"""
为此我创建了 2 个结构:
struct MovesResponse: Codable {
let moves: [[MoveModel]]
}
struct MoveModel: Codable {
let mine: Int
let words: String
let letters: String
}
并调用:
let decoder = JSONDecoder()
if let movesData = jsonMoves.data(using: .utf8),
let movesModel = try? decoder.decode(MovesResponse.self, from: movesData),
movesModel.count > 0 // does not compile
{
print("Parsed moves: ", movesModel)
} else {
print("Can not parse moves")
}
不幸的是,上面的代码给我编译错误:
Value of type 'MovesResponse' has no member 'count'
当我删除该行并将 try?
更改为 try!
以查看异常时,我得到错误:
Fatal error: 'try!' expression unexpectedly raised an error: Swift.DecodingError.dataCorrupted(Swift.DecodingError.Context(codingPath: [], debugDescription: "The given data was not valid JSON.", underlyingError: Optional(Error Domain=NSCocoaErrorDomain Code=3840 "Invalid value around line 3, column 12." UserInfo={NSDebugDescription=Invalid value around line 3, column 12., NSJSONSerializationErrorIndex=29})))
作为一个 Swift 新手,我认为结构 MoveModel
是错误的。请帮忙
另外我想知道是否可以将内部数组的三个元素称为“mine”、“words”、“letters”?
更新:
我已按照 Joakim 的建议将 jsonMoves
中的单引号更改为双引号(谢谢!),现在的错误是:
Fatal error: 'try!' expression unexpectedly raised an error: Swift.DecodingError.typeMismatch(Swift.Dictionary<Swift.String, Any>, Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: "moves", intValue: nil), _JSONKey(stringValue: "Index 0", intValue: 0), _JSONKey(stringValue: "Index 0", intValue: 0)], debugDescription: "Expected to decode Dictionary<String, Any> but found a number instead.", underlyingError: nil))
您可以使用 MoveModel
,但由于每个内部数组代表 MoveModel
的一个实例,因此您需要将第一个结构更改为
struct MovesResponse: Codable {
let moves: [MoveModel]
}
然后您需要 MoveModel
中的自定义 init(from:)
,它使用未加密的容器而不是编码键将每个数组解码为 MoveModel
对象。
init(from decoder: Decoder) throws {
var container = try decoder.unkeyedContainer()
mine = try container.decode(Int.self)
words = try container.decode(String.self)
letters = try container.decode(String.self)
}
与其使用 try?
并打印硬编码消息,我建议您捕获错误并打印它
let decoder = JSONDecoder()
do {
let movesModel = try decoder.decode(MovesResponse.self, from: data)
print(movesModel)
} catch {
print(error)
}
在 Swift Playground 中,我尝试解析以下数据:
let jsonMoves:String =
"""
{ "moves":
[
[0, 'CAT (7)', 'ACT'],
[1, 'EXTRA (14)', 'ERXT'],
[0, 'TOP (22)', 'PO'],
[1, 'TOY (9)', 'Y']
]
}
"""
为此我创建了 2 个结构:
struct MovesResponse: Codable {
let moves: [[MoveModel]]
}
struct MoveModel: Codable {
let mine: Int
let words: String
let letters: String
}
并调用:
let decoder = JSONDecoder()
if let movesData = jsonMoves.data(using: .utf8),
let movesModel = try? decoder.decode(MovesResponse.self, from: movesData),
movesModel.count > 0 // does not compile
{
print("Parsed moves: ", movesModel)
} else {
print("Can not parse moves")
}
不幸的是,上面的代码给我编译错误:
Value of type 'MovesResponse' has no member 'count'
当我删除该行并将 try?
更改为 try!
以查看异常时,我得到错误:
Fatal error: 'try!' expression unexpectedly raised an error: Swift.DecodingError.dataCorrupted(Swift.DecodingError.Context(codingPath: [], debugDescription: "The given data was not valid JSON.", underlyingError: Optional(Error Domain=NSCocoaErrorDomain Code=3840 "Invalid value around line 3, column 12." UserInfo={NSDebugDescription=Invalid value around line 3, column 12., NSJSONSerializationErrorIndex=29})))
作为一个 Swift 新手,我认为结构 MoveModel
是错误的。请帮忙
另外我想知道是否可以将内部数组的三个元素称为“mine”、“words”、“letters”?
更新:
我已按照 Joakim 的建议将 jsonMoves
中的单引号更改为双引号(谢谢!),现在的错误是:
Fatal error: 'try!' expression unexpectedly raised an error: Swift.DecodingError.typeMismatch(Swift.Dictionary<Swift.String, Any>, Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: "moves", intValue: nil), _JSONKey(stringValue: "Index 0", intValue: 0), _JSONKey(stringValue: "Index 0", intValue: 0)], debugDescription: "Expected to decode Dictionary<String, Any> but found a number instead.", underlyingError: nil))
您可以使用 MoveModel
,但由于每个内部数组代表 MoveModel
的一个实例,因此您需要将第一个结构更改为
struct MovesResponse: Codable {
let moves: [MoveModel]
}
然后您需要 MoveModel
中的自定义 init(from:)
,它使用未加密的容器而不是编码键将每个数组解码为 MoveModel
对象。
init(from decoder: Decoder) throws {
var container = try decoder.unkeyedContainer()
mine = try container.decode(Int.self)
words = try container.decode(String.self)
letters = try container.decode(String.self)
}
与其使用 try?
并打印硬编码消息,我建议您捕获错误并打印它
let decoder = JSONDecoder()
do {
let movesModel = try decoder.decode(MovesResponse.self, from: data)
print(movesModel)
} catch {
print(error)
}