import Foundation | |
// Inspired by https://gist.github.com/mbuchetics/c9bc6c22033014aa0c550d3b4324411a | |
struct JSONCodingKeys: CodingKey { | |
var stringValue: String | |
init?(stringValue: String) { | |
self.stringValue = stringValue | |
} | |
var intValue: Int? | |
init?(intValue: Int) { | |
self.init(stringValue: "\(intValue)") | |
self.intValue = intValue | |
} | |
} | |
extension KeyedDecodingContainer { | |
func decode(_ type: Dictionary<String, Any>.Type, forKey key: K) throws -> Dictionary<String, Any> { | |
let container = try self.nestedContainer(keyedBy: JSONCodingKeys.self, forKey: key) | |
return try container.decode(type) | |
} | |
func decodeIfPresent(_ type: Dictionary<String, Any>.Type, forKey key: K) throws -> Dictionary<String, Any>? { | |
guard contains(key) else { | |
return nil | |
} | |
return try decode(type, forKey: key) | |
} | |
func decode(_ type: Array<Any>.Type, forKey key: K) throws -> Array<Any> { | |
var container = try self.nestedUnkeyedContainer(forKey: key) | |
return try container.decode(type) | |
} | |
func decodeIfPresent(_ type: Array<Any>.Type, forKey key: K) throws -> Array<Any>? { | |
guard contains(key) else { | |
return nil | |
} | |
return try decode(type, forKey: key) | |
} | |
func decode(_ type: Dictionary<String, Any>.Type) throws -> Dictionary<String, Any> { | |
var dictionary = Dictionary<String, Any>() | |
for key in allKeys { | |
if let if let boolValue = try? decode(Bool.self, forKey: key) { | |
dictionary[key.stringValue] = boolValue | |
} else if let stringValue = try? decode(String.self, forKey: key) { | |
dictionary[key.stringValue] = stringValue | |
} else intValue = try? decode(Int.self, forKey: key) { | |
dictionary[key.stringValue] = intValue | |
} else if let doubleValue = try? decode(Double.self, forKey: key) { | |
dictionary[key.stringValue] = doubleValue | |
} else if let fileMetaData = try? decode(Asset.FileMetadata.self, forKey: key) { | |
dictionary[key.stringValue] = fileMetaData // Custom contentful type. | |
} else if let nestedDictionary = try? decode(Dictionary<String, Any>.self, forKey: key) { | |
dictionary[key.stringValue] = nestedDictionary | |
} else if let nestedArray = try? decode(Array<Any>.self, forKey: key) { | |
dictionary[key.stringValue] = nestedArray | |
} | |
} | |
return dictionary | |
} | |
} | |
extension UnkeyedDecodingContainer { | |
mutating func decode(_ type: Array<Any>.Type) throws -> Array<Any> { | |
var array: [Any] = [] | |
while isAtEnd == false { | |
if let value = try? decode(Bool.self) { | |
array.append(value) | |
} else if let value = try? decode(Double.self) { | |
array.append(value) | |
} else if let value = try? decode(String.self) { | |
array.append(value) | |
} else if let nestedDictionary = try? decode(Dictionary<String, Any>.self) { | |
array.append(nestedDictionary) | |
} else if let nestedArray = try? decode(Array<Any>.self) { | |
array.append(nestedArray) | |
} | |
} | |
return array | |
} | |
mutating func decode(_ type: Dictionary<String, Any>.Type) throws -> Dictionary<String, Any> { | |
let nestedContainer = try self.nestedContainer(keyedBy: JSONCodingKeys.self) | |
return try nestedContainer.decode(type) | |
} | |
} |
This comment has been minimized.
This comment has been minimized.
@hashemp206 done, good catch ;-) |
This comment has been minimized.
This comment has been minimized.
@loudmouth, did you have a license in mind for this gist? Looks just like the kind of thing I've been looking for, to work with my Codable stuff for JSON parsing... Good work! |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
Correcting the above link from @sakrist: https://github.com/3D4Medical/glTFSceneKit/blob/master/Sources/glTFSceneKit/GLTF/JSONCodingKeys.swift |
This comment has been minimized.
This comment has been minimized.
@loudmouth
|
This comment has been minimized.
This comment has been minimized.
One more check to see if the value of the key is null then return nil
|
This comment has been minimized.
This comment has been minimized.
dude! you save my time |
This comment has been minimized.
This comment has been minimized.
Thanks for this code! One of our API's returned an array where one of the values was 'null', which got the [Any] decoder into an infinite loop.
|
This comment has been minimized.
This comment has been minimized.
@ChiellieNL thanks for sharing that fix! I had to replace the line with Here is my version with decoding (original post), encoding (thank you @sakrist!) and the null fix from above. I also changed the types to the modern syntax of https://gist.github.com/mikebuss/17142624da4baf9cdcc337861e256533 |
This comment has been minimized.
This comment has been minimized.
@converted2mac I guess Github doesn't give notifications for comments on Gists Anyway, no license, i'd say go ahead and use the code as you need ;-) |
This comment has been minimized.
This comment has been minimized.
@mikebuss |
This comment has been minimized.
This comment has been minimized.
Thanks for sharing this! I really need it :) |
This comment has been minimized.
This comment has been minimized.
Thanks for this. I think if you renamed the gist to end in |
This comment has been minimized.
This comment has been minimized.
Thanks for sharing this |
This comment has been minimized.
change decoder to check for bool at first. because
true
will be decoded to int 1, so check for bool will drop