我很好奇如何使用String
键和Encodable
值将字典编码为JSON。
例如:
let dict: [String: Encodable] = [
"Int": 1,
"Double": 3.14,
"Bool": false,
"String": "test"
]
此dict
中的键都是String
类型,但是值的类型各不相同。
但是,所有这些类型都可以在JSON中使用。
我想知道是否有一种方法可以在Swift 4中使用JSONEncoder
将此dict
编码为JSON Data
。
我确实知道还有其他方法可以不使用JSONEncoder
来实现,但是我只是想知道JSONEncoder
是否能够管理此问题。
Dictionary
的扩展名中确实有func encode(to encoder: Encoder) throws
,但这仅适用于约束Key: Encodable, Key: Hashable, Value: Encodable
,而对于我们的dict
,它需要约束Key: Encodable, Key: Hashable, Value == Encodable
为此拥有一个struct
就足以使用JSONEncoder
struct Test: Encodable {
let int = 1
let double = 3.14
let bool = false
let string = "test"
}
但是,我很想知道是否可以在不指定具体类型的情况下仅通过Encodable
协议来完成此操作。
答案 0 :(得分:4)
只是想出了一种使用包装器实现此目的的方法:
struct EncodableWrapper: Encodable {
let wrapped: Encodable
func encode(to encoder: Encoder) throws {
try self.wrapped.encode(to: encoder)
}
}
let dict: [String: Encodable] = [
"Int": 1,
"Double": 3.14,
"Bool": false,
"String": "test"
]
let wrappedDict = dict.mapValues(EncodableWrapper.init(wrapped:))
let jsonEncoder = JSONEncoder()
jsonEncoder.outputFormatting = .prettyPrinted
let jsonData = try! jsonEncoder.encode(wrappedDict)
let json = String(decoding: jsonData, as: UTF8.self)
print(json)
结果如下:
{ “ Double”:3.1400000000000001, “ String”:“ test”, “布尔”:否, “整数”:1 }
我仍然不满意。如果还有其他方法,我很高兴看到它。
谢谢!
JSONEncoder
的扩展名:extension JSONEncoder {
private struct EncodableWrapper: Encodable {
let wrapped: Encodable
func encode(to encoder: Encoder) throws {
try self.wrapped.encode(to: encoder)
}
}
func encode<Key: Encodable>(_ dictionary: [Key: Encodable]) throws -> Data {
let wrappedDict = dictionary.mapValues(EncodableWrapper.init(wrapped:))
return try self.encode(wrappedDict)
}
}
let dict: [String: Encodable] = [
"Int": 1,
"Double": 3.14,
"Bool": false,
"String": "test"
]
let jsonEncoder = JSONEncoder()
jsonEncoder.outputFormatting = .prettyPrinted
let jsonData = try! jsonEncoder.encode(dict)
let json = String(decoding: jsonData, as: UTF8.self)
print(json)
结果:
{ “整数”:1 “ Double”:3.1400000000000001, “布尔”:否, “ String”:“测试” }
private extension Encodable {
func encode(to container: inout SingleValueEncodingContainer) throws {
try container.encode(self)
}
}
extension JSONEncoder {
private struct EncodableWrapper: Encodable {
let wrapped: Encodable
func encode(to encoder: Encoder) throws {
var container = encoder.singleValueContainer()
try self.wrapped.encode(to: &container)
}
}
func encode<Key: Encodable>(_ dictionary: [Key: Encodable]) throws -> Data {
let wrappedDict = dictionary.mapValues(EncodableWrapper.init(wrapped:))
return try self.encode(wrappedDict)
}
}
答案 1 :(得分:1)
由于使用Encodable
协议,因此您需要一个包装器,以便知道哪个项目可以更容易地进行编码。
我建议使用一个名为JSONValue
的枚举,该枚举对所有Int
,String
,Double
,Array
,{{1} }案件。那么您可以使用类型安全的方式编写JSON。
此link也会有所帮助。
这是我的用法:
Dictionary
然后制作indirect enum JSONValue {
case string(String)
case int(Int)
case double(Double)
case bool(Bool)
case object([String: JSONValue])
case array([JSONValue])
case encoded(Encodable)
}
并为每种情况编写编码代码。