2017-07-20 2 views

Antwort

35

Wenn Sie nicht ein wenig Verschiebung von Daten dagegen um Sie so etwas wie diese verwenden:

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 
    } 
} 

oder ein optionales varient

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] } 
    } 
} 

Unter der Annahme, Foo zu Codable entspricht oder wirklich Encodable dann kannst du das tun.

let struct = Foo(a: 1, b: 2) 
let dict = try struct.asDictionary() 
let optionalDict = struct.dictionary 

Wenn Sie in die andere Richtung (init(any)) gehen wollen, werfen Sie einen Blick auf diese Init an object conforming to Codable with a dictionary/array

3

Ich bin mir nicht sicher, ob es der beste Weg ist, aber Sie können auf jeden Fall so etwas wie:

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

Dies würde nur für Strukturen mit allen Eigenschaften der gleichen Art funktionieren –

0

ich eine schnelle gist schrieb, dies zu umgehen (nicht das Kodierbare Protokoll). Seien Sie vorsichtig, es gibt keine type-check Werte ein und arbeitet nicht rekursiv mit codierbaren Werten.

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

, daran zu denken kommen, stellt sich die Frage keine Antwort im allgemeinen Fall haben, da die Encodable Instanz etwas nicht serializable in ein Wörterbuch sein kann, wie ein Array:

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

Ansonsten habe ich something similar as a framework geschrieben.

0

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

6

Ich schaffe haben eine Bibliothek CodableFirebase genannt und es ursprünglichen Zweck war es zu benutzen, mit Firebase Database, aber es ist tatsächlich was Sie brauchen: es erstellt ein Wörterbuch oder einen anderen Typ wie in JSONDecoder, aber Sie müssen nicht die doppelte Konvertierung hier tun, wie Sie in anderen Antworten tun. So wäre es etwa so aussehen:

import CodableFirebase 

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

Ich denke auf jeden Fall, dass es einen gewissen Wert ist in der Lage, nur Codable verwenden zu/von Wörterbüchern zu kodieren, ohne die Absicht, jemals JSON/Plists/was auch immer zu schlagen. Es gibt viele APIs, die Ihnen nur ein Wörterbuch zurückgeben, oder ein Wörterbuch erwarten, und es ist nett, sie leicht mit Swift-Strukturen oder -Objekten austauschen zu können, ohne endlosen Standardcode schreiben zu müssen.

Ich habe Runde mit Code auf der Grundlage der Foundation JSONEncoder.swift Quelle (die tatsächlich implementiert Wörterbuch Codierung/Decodierung intern implementiert, aber exportiert es nicht). ziemlich rau, aber ich habe es https://github.com/elegantchaos/DictionaryCoding

Es ist immer noch ein wenig erweitert, so dass es zum Beispiel in fehlenden Werten mit Standardwerten füllen kann, wenn Decodierung:

Der Code kann hier gefunden werden.

Verwandte Themen