如何在Swift中解析具有与类型相关的子对象的JSON对象? [英] How do I parse a JSON object that has type-dependent sub-objects, in Swift?
本文介绍了如何在Swift中解析具有与类型相关的子对象的JSON对象?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!
问题描述
我有以下JSON对象:
I have the following JSON object:
[{
"type": "foo",
"props": {
"word": "hello"
}
}, {
"type": "bar",
"props": {
"number": 42
}
}]
根据type
中存储的类型,props
中的对象具有不同的键.所以,我尝试了一些逻辑
Depending on the type stored in type
, the object in props
has different keys. So, I tried with some logic
struct MyObject : Codable {
struct FooProps { let word: String }
struct BarProps { var number: Int }
enum PropTypes { case FooProps, BarProps }
let type: String
let props: PropTypes?
enum CodingKeys : CodingKey {
case type, props
}
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
type = try values.decode(String.self, forKey: .type)
switch type {
case "foo":
props = try values.decode(FooProps.self, forKey: .props)
case "bar":
props = try values.decode(BarProps.self, forKey: .props)
default:
props = nil
}
}
}
但没有运气
error: jsontest.playground:10:8: error: type 'MyObject' does not conform to protocol 'Encodable'
struct MyObject : Codable {
^
jsontest.playground:16:9: note: cannot automatically synthesize 'Encodable' because 'MyObject.PropTypes?' does not conform to 'Encodable'
let props: PropTypes?
^
error: jsontest.playground:27:39: error: cannot convert value of type 'MyObject.FooProps.Type' to expected argument type 'MyObject.PropTypes?.Type'
props = try values.decode(FooProps.self, forKey: .props)
^~~~~~~~
error: jsontest.playground:29:39: error: cannot convert value of type 'MyObject.BarProps.Type' to expected argument type 'MyObject.PropTypes?.Type'
props = try values.decode(BarProps.self, forKey: .props)
^~~~~~~~
然后,我认为某些类魔法可能会做到
Then, I thought some class magic would probably do
class PropTypes : Codable { }
class FooProps : PropTypes { var word: String = "Default String" }
class BarProps : PropTypes { var number: Int = -1 }
class MyObject : Codable {
let type: String
var props: PropTypes?
enum CodingKeys : CodingKey {
case type, props
}
...
但是当我执行dump
解析结果时,我只会得到默认值
but when I do dump
the result of the parsing, I only get the default values
▿ 2 elements
▿ __lldb_expr_32.MyObject #0
- type: "foo"
▿ props: Optional(__lldb_expr_32.FooProps)
▿ some: __lldb_expr_32.FooProps #1
- super: __lldb_expr_32.PropTypes
- word: "Default String"
▿ __lldb_expr_32.MyObject #2
- type: "bar"
▿ props: Optional(__lldb_expr_32.BarProps)
▿ some: __lldb_expr_32.BarProps #3
- super: __lldb_expr_32.PropTypes
- number: -1
我的问题是:我想念什么?可以做到吗?
My question is: what am I missing? Can this be done at all?
编辑:按照凯文·巴拉德(Kevin Ballard)的建议,出现以下错误:
EDIT Following Kevin Ballard's suggestion, I get the following errors:
error: jsontest.playground:15:37: error: no 'decode' candidates produce the expected contextual result type 'MyObject.FooProps'
props = try .foo(values.decode(FooProps.self, forKey: .props))
^
jsontest.playground:15:37: note: overloads for 'decode' exist with these result types: Bool, Int, Int8, Int16, Int32, Int64, UInt, UInt8, UInt16, UInt32, UInt64, Float, Double, String, T
props = try .foo(values.decode(FooProps.self, forKey: .props))
^
error: jsontest.playground:17:37: error: no 'decode' candidates produce the expected contextual result type 'MyObject.BarProps'
props = try .bar(values.decode(BarProps.self, forKey: .props))
^
jsontest.playground:17:37: note: overloads for 'decode' exist with these result types: Bool, Int, Int8, Int16, Int32, Int64, UInt, UInt8, UInt16, UInt32, UInt64, Float, Double, String, T
props = try .bar(values.decode(BarProps.self, forKey: .props))
^
推荐答案
看看您原来列出的错误,有两个不同的问题.
Looking at your original listed errors, there are two distinct issues.
- 您声明符合
Codable
,但是错误告诉您它不能自动合成Encodable
.您的问题不是关于编码,而是关于解码,因此,我想说的是,遵循Decodable
而不是Codable
(或自己实现编码). -
props
的类型为PropTypes?
,其中PropTypes
是枚举.您正在解码FooProps
或BarProps
,然后将结果填充到props
中.您需要将结果包装在枚举中.同样,您的枚举定义为错误,您有名为FooProps
和BarProps
的个案,它们不带有值.应该像{ case foo(FooProps), bar(BarPros) }
这样重新定义它.
- You declared conformance to
Codable
, but the errors are telling you it cannot automatically synthesizeEncodable
. Your question isn't about encoding, but decoding, so for this I'd say just conform toDecodable
instead ofCodable
(or implement encoding yourself). props
is of typePropTypes?
, wherePropTypes
is an enum. You're decoding eitherFooProps
orBarProps
, and stuffing the result intoprops
. You need to wrap the result in the enum instead. Also your enum is defined wrong, you have cases namedFooProps
andBarProps
, which don't carry values. It should be redefined like{ case foo(FooProps), bar(BarPros) }
instead.
总的来说,这看起来像
struct MyObject : Decodable {
struct FooProps : Decodable { let word: String }
struct BarProps : Decodable { var number: Int }
enum PropTypes { case foo(FooProps), bar(BarProps) }
let type: String
let props: PropTypes?
enum CodingKeys : CodingKey {
case type, props
}
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
type = try values.decode(String.self, forKey: .type)
switch type {
case "foo":
props = try .foo(values.decode(FooProps.self, forKey: .props))
case "bar":
props = try .bar(values.decode(BarProps.self, forKey: .props))
default:
props = nil
}
}
}
这篇关于如何在Swift中解析具有与类型相关的子对象的JSON对象?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!
查看全文