2017-07-20 38 views
17

我有一个结构实现了Swift 4的Codable。是否有一种简单的内置方式将该结构编码到字典中?如何使用Swift的Codable编码成字典?

let struct = Foo(a: 1, b: 2) 
let dict = something(struct) 
// now dict is ["a": 1, "b": 2] 

回答

35

如果你不介意位数据的移位的周围,你可以使用这样的事情:

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

3

我不知道这是否是最好的方式,但你绝对可以做这样的事情:

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) 
+1

这只会与同类型的所有属性结构工作 –

0

我写了一个快速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) 
} 
-2

试想想起来了,这个问题并没有在一般情况下一个答案,因为Encodable实例可能是一些不可序列化到一个字典,如数组:

let payload = [1, 2, 3] 
let encoded = try JSONEncoder().encode(payload) // "[1,2,3]" 

除此之外,我写了something similar as a framework

0

let dict = try JSONSerialization.jsonObject(with: try JSONEncoder().encode(struct), options: []) as? [String: Any]

6

我已创建一个库调用CodableFirebase,它的最初目的是与使用它火力地堡数据库,但它实际上你所需要的:它会创建一个词典或任何其他类型就像JSONDecoder但像你在其他的答案你不需要在这里做了双转换。因此,它看起来是这样的:

import CodableFirebase 

let model = Foo(a: 1, b: 2) 
let dict = try! FirebaseEncoder().encode(model) 
0

我绝对认为有在短短能够使用Codable从字典编码为/一定的价值,而没有触及JSON/Plist档案的意图/不管。有很多API只是给你一个字典,或者期望一个字典,并且能够很容易地与Swift结构或对象交换它们,而不必编写无穷无尽的样板代码。

我一直在玩一轮基于基金会JSONEncoder.swift源代码的一些(实际上确实在内部执行字典编码/解码,但不出口的话)。

的代码可以在这里找到:https://github.com/elegantchaos/DictionaryCoding

它仍然是相当粗糙,但我已经扩大了它一下,这样,例如,它可以在解码时默认缺失值填补。