如何使用Swift的Codable编码成字典?
我有一个结构实现了Swift 4的Codable
。是否有一种简单的内置方式将该结构编码到字典中?如何使用Swift的Codable编码成字典?
let struct = Foo(a: 1, b: 2)
let dict = something(struct)
// now dict is ["a": 1, "b": 2]
如果你不介意位数据的移位的周围,你可以使用这样的事情:
extension Encodable {
func asDictionary() throws -> [String: Any] {
let data = try JSONEncoder().encode(self)
guard let dictionary = try JSONSerialization.jsonObject(with: data, options: .allowFragments) as? [String: Any] else {
throw NSError()
}
return dictionary
}
}
或可选的变体光盘
extension Encodable {
var dictionary: [String: Any]? {
guard let data = try? JSONEncoder().encode(self) else { return nil }
return (try? JSONSerialization.jsonObject(with: data, options: .allowFragments)).flatMap { $0 as? [String: Any] }
}
}
假设Foo
符合Codable
还是真的Encodable
那么你可以做到这一点。
let struct = Foo(a: 1, b: 2)
let dict = try struct.asDictionary()
let optionalDict = struct.dictionary
如果你想要去的其他方式(init(any)
),看看这Init an object conforming to Codable with a dictionary/array
我不知道这是否是最好的方式,但你绝对可以做这样的事情:
struct Foo: Codable {
var a: Int
var b: Int
init(a: Int, b: Int) {
self.a = a
self.b = b
}
}
let foo = Foo(a: 1, b: 2)
let dict = try JSONDecoder().decode([String: Int].self, from: JSONEncoder().encode(foo))
print(dict)
我写了一个快速gist来处理这个(不使用可编码的协议)。请注意,它不会对任何值进行类型检查,并且不会对可编码的值进行递归操作。
class DictionaryEncoder {
var result: [String: Any]
init() {
result = [:]
}
func encode(_ encodable: DictionaryEncodable) -> [String: Any] {
encodable.encode(self)
return result
}
func encode<T, K>(_ value: T, key: K) where K: RawRepresentable, K.RawValue == String {
result[key.rawValue] = value
}
}
protocol DictionaryEncodable {
func encode(_ encoder: DictionaryEncoder)
}
试想想起来了,这个问题并没有在一般情况下一个答案,因为Encodable
实例可能是一些不可序列化到一个字典,如数组:
let payload = [1, 2, 3]
let encoded = try JSONEncoder().encode(payload) // "[1,2,3]"
除此之外,我写了something similar as a framework。
let dict = try JSONSerialization.jsonObject(with: try JSONEncoder().encode(struct), options: []) as? [String: Any]
我已创建一个库调用CodableFirebase,它的最初目的是与使用它火力地堡数据库,但它实际上你所需要的:它会创建一个词典或任何其他类型就像JSONDecoder
但像你在其他的答案你不需要在这里做了双转换。因此,它看起来是这样的:
import CodableFirebase
let model = Foo(a: 1, b: 2)
let dict = try! FirebaseEncoder().encode(model)
我绝对认为有在短短能够使用Codable
从字典编码为/一定的价值,而没有触及JSON/Plist档案的意图/不管。有很多API只是给你一个字典,或者期望一个字典,并且能够很容易地与Swift结构或对象交换它们,而不必编写无穷无尽的样板代码。
我一直在玩一轮基于基金会JSONEncoder.swift源代码的一些(实际上确实在内部执行字典编码/解码,但不出口的话)。
的代码可以在这里找到:https://github.com/elegantchaos/DictionaryCoding
它仍然是相当粗糙,但我已经扩大了它一下,这样,例如,它可以在解码时默认缺失值填补。
这只会与同类型的所有属性结构工作 –