2017-07-20 33 views

Trả lời

35

Nếu bạn không nhớ một chút chuyển dữ liệu xung quanh bạn có thể sử dụng một cái gì đó như thế này:

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

Hoặc một varient tùy chọn

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

Giả sử Foo phù hợp với Codable hoặc thực sự Encodable sau đó bạn có thể làm điều này.

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

Nếu bạn muốn đi theo con đường khác (init(any)), hãy xem này Init an object conforming to Codable with a dictionary/array

3

Tôi không chắc chắn nếu đó là cách tốt nhất nhưng bạn chắc chắn có thể làm điều gì đó như:

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

Điều này sẽ chỉ hoạt động đối với các cấu trúc có tất cả các thuộc tính cùng loại –

0

tôi đã viết một cách nhanh chóng gist để xử lý này (không sử dụng giao thức Codable). Hãy cẩn thận, nó không gõ-kiểm tra bất kỳ giá trị và không làm việc đệ quy về giá trị được mã hóa.

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

Hãy đến với suy nghĩ của nó, câu hỏi không có câu trả lời trong trường hợp tổng quát, vì dụ Encodable có thể là cái gì đó không serializable vào một cuốn từ điển, chẳng hạn như một mảng:

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

Ngoài ra, tôi đã viết something similar as a framework.

0

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

6

tôi đã tạo ra một thư viện gọi CodableFirebase và nó mục đích ban đầu là để sử dụng nó với Cơ sở dữ liệu Firebase, nhưng nó thực sự là những gì bạn cần: nó tạo ra một từ điển hoặc bất kỳ loại nào khác giống như trong JSONDecoder nhưng bạn không cần thực hiện chuyển đổi kép ở đây giống như bạn làm trong các câu trả lời khác. Vì vậy, nó sẽ giống như thế:

import CodableFirebase 

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

Tôi chắc chắn rằng có một số giá trị chỉ trong việc có thể sử dụng để mã hóa Codable đến/từ điển, mà không có ý định bao giờ đánh JSON/Plist/bất cứ điều gì. Có rất nhiều API chỉ cung cấp cho bạn một từ điển, hoặc mong đợi một từ điển, và thật tuyệt khi có thể trao đổi chúng một cách dễ dàng với các cấu trúc hoặc các đối tượng Swift, mà không cần phải viết mã boilerplate vô tận.

Tôi đã chơi vòng với một số mã dựa trên nguồn Foundation JSONEncoder.swift (thực sự thực hiện mã hóa/giải mã từ điển nội bộ, nhưng không xuất nó).

Mã này có thể được tìm thấy ở đây: https://github.com/elegantchaos/DictionaryCoding

Nó vẫn còn khá thô, nhưng tôi đã mở rộng nó một chút do đó, ví dụ, nó có thể điền vào thiếu giá trị với giá trị mặc định khi giải mã.

Các vấn đề liên quan