Created
January 18, 2018 11:35
-
-
Save rizumita/d51a6e4c2f1232111a2339c206cfaaa0 to your computer and use it in GitHub Desktop.
Decode [String:Any] property by Decodable in Swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
struct AnyCodingKeys: CodingKey { | |
var stringValue: String | |
var intValue: Int? | |
init?(stringValue: String) { self.stringValue = stringValue } | |
init?(intValue: Int) { | |
self.stringValue = String(intValue) | |
self.intValue = intValue | |
} | |
} | |
extension KeyedDecodingContainer { | |
func decode(_ type: [Any].Type, forKey key: K) throws -> [Any] { | |
var container = try self.nestedUnkeyedContainer(forKey: key) | |
return try container.decode(type) | |
} | |
func decodeIfPresent(_ type: [Any].Type, forKey key: K) throws -> [Any]? { | |
guard contains(key) else { return .none } | |
return try decode(type, forKey: key) | |
} | |
func decode(_ type: [String:Any].Type, forKey key: K) throws -> [String:Any] { | |
let container = try nestedContainer(keyedBy: AnyCodingKeys.self, forKey: key) | |
return try container.decode(type) | |
} | |
func decodeIfPresent(_ type: [String:Any].Type, forKey key: K) throws -> [String:Any]? { | |
guard contains(key) else { return .none } | |
return try decode(type, forKey: key) | |
} | |
func decode(_ type: [String:Any].Type) throws -> [String:Any] { | |
var dictionary = [String:Any]() | |
allKeys.forEach { key in | |
if let value = try? decode(Bool.self, forKey: key) { | |
dictionary[key.stringValue] = value | |
} else if let value = try? decode(String.self, forKey: key) { | |
dictionary[key.stringValue] = value | |
} else if let value = try? decode(Int64.self, forKey: key) { | |
dictionary[key.stringValue] = value | |
} else if let value = try? decode(Double.self, forKey: key) { | |
dictionary[key.stringValue] = value | |
} else if let value = try? decode([String:Any].self, forKey: key) { | |
dictionary[key.stringValue] = value | |
} else if let value = try? decode([Any].self, forKey: key) { | |
dictionary[key.stringValue] = value | |
} | |
} | |
return dictionary | |
} | |
} | |
extension UnkeyedDecodingContainer { | |
mutating func decode(_ type: [Any].Type) throws -> [Any] { | |
var array = [Any]() | |
while isAtEnd == false { | |
if let value = try? decode(Bool.self) { | |
array.append(value) | |
} else if let value = try? decode(String.self) { | |
array.append(value) | |
} else if let value = try? decode(Int64.self) { | |
array.append(value) | |
} else if let value = try? decode(Double.self) { | |
array.append(value) | |
} else if let value = try? decode([String:Any].self) { | |
array.append(value) | |
} else if let value = try? decode([Any].self) { | |
array.append(value) | |
} | |
} | |
return array | |
} | |
mutating func decode(_ type: [String:Any].Type) throws -> [String:Any] { | |
let nestedContainer = try self.nestedContainer(keyedBy: AnyCodingKeys.self) | |
return try nestedContainer.decode(type) | |
} | |
} | |
struct A: Decodable { | |
let title: String | |
let payload: Payload | |
struct Payload: Decodable { | |
let items: [String:Any] | |
public init(from decoder: Decoder) throws { | |
let container = try decoder.container(keyedBy: AnyCodingKeys.self) | |
items = try container.decode([String:Any].self) | |
} | |
} | |
} | |
let jsonString = """ | |
{ | |
"title":"abc", | |
"payload": { | |
"int": 1, | |
"string": "2", | |
"array": { | |
"bool": true, | |
"double": 2.34 | |
} | |
} | |
} | |
""" | |
let jsonData = jsonString.data(using: .utf8)! | |
let a = try! JSONDecoder().decode(A.self, from: jsonData) | |
print(a) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment