Created
April 27, 2019 18:41
-
-
Save hamdan/c207bf6567052a988651eeb2e39def67 to your computer and use it in GitHub Desktop.
Extensions giving Swift's decodable API type inference super powers
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
// Private supporting types | |
private struct AnyCodingKey: CodingKey { | |
var stringValue: String | |
var intValue: Int? | |
init(_ string: String) { | |
stringValue = string | |
} | |
init?(stringValue: String) { | |
self.stringValue = stringValue | |
} | |
init?(intValue: Int) { | |
self.intValue = intValue | |
self.stringValue = String(intValue) | |
} | |
} | |
// Safe Decoding Container | |
public struct SafeDecodingContainer<Base: Decodable>: Decodable { | |
public let value: Base? | |
public init(from decoder: Decoder) throws { | |
do { | |
let container = try decoder.singleValueContainer() | |
self.value = try container.decode(Base.self) | |
} catch { | |
print("Mapping ERROR: \(error)") | |
self.value = nil | |
} | |
} | |
} | |
//Helpers | |
public extension Decoder { | |
func decode<T: Decodable>(_ key: String, as type: T.Type = T.self) throws -> T { | |
return try decode(AnyCodingKey(key), as: type) | |
} | |
func decode<T: Decodable, K: CodingKey>(_ key: K, as type: T.Type = T.self) throws -> T { | |
let container = try self.container(keyedBy: K.self) | |
return try container.decode(type, forKey: key) | |
} | |
func decodeGuard<T: Decodable>(_ key: String) throws -> T? { | |
return try? self.decodeGuard(T.self, forKey: AnyCodingKey(key)) | |
} | |
func decodeGuard<T: Decodable, K: CodingKey>(_ type: T.Type, forKey key: K) throws -> T? { | |
let container = try? self.container(keyedBy: K.self) | |
return tryOrNil { (try container?.decode(T.self, forKey: key)) } | |
} | |
func decodeGuardArray<T: Decodable>(_ key: String) throws -> [T] { | |
return try decodeGuardArray(T.self, forKey: AnyCodingKey(key)) | |
} | |
func decodeGuardArray<T: Decodable, K: CodingKey>(_ type: T.Type, forKey key: K) throws -> [T] { | |
let container = try? self.container(keyedBy: K.self) | |
let array = tryOrNil { (try container?.decode([T].self, forKey: key)) } | |
return array?.compactMap { $0 } ?? [] | |
} | |
} | |
// example code | |
public struct SaveDecodeClass: Codable { | |
public var token: String = "" | |
public var urlString: String = "" | |
public init(from decoder: Decoder) throws { | |
token = try decoder.decodeGuard("token") ?? "" | |
urlString = try decoder.decodeGuard("urlString") ?? "" | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment