Skip to content

Instantly share code, notes, and snippets.

@vinhnx
Last active July 9, 2019 04:11
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save vinhnx/5a9c13bd7e037d72092ec1cbc85b6bde to your computer and use it in GitHub Desktop.
Save vinhnx/5a9c13bd7e037d72092ec1cbc85b6bde to your computer and use it in GitHub Desktop.
decode Swift enum and Date for Codable properties
import Foundation
protocol AssetTypeConvertible {
// conformer just need to declare conformance to `AssetTypeConvertible` and will be auto inferred as generic `Value`
// and Xcode auto completion just works
// see AssetType below
associatedtype Value = Self
static func convertToEnum(from rawValue: String) -> Value
}
extension KeyedDecodingContainerProtocol {
func decodeEnumFromRawValue<T: AssetTypeConvertible>(_ rawValue: String) throws -> T {
guard let result = T.convertToEnum(from: rawValue) as? T else {
// this should never happen, since we inferred type
fatalError("This should never happen, since we inferred type, but here is to not force cast")
}
return result
}
}
struct Utilities {}
extension Utilities {
static func decodeDate<T: CodingKey>(key: T, in container: KeyedDecodingContainer<T>, using dateFormatter: DateFormatter) throws -> Date {
let _decoded = try container.decodeIfPresent(String.self, forKey: key) ?? ""
return _decoded.isEmpty ? Date() : (dateFormatter.date(from: _decoded) ?? Date())
}
}
// AssetTypeConvertible usage
enum AssetType: String {
case series
case movie
case sports
case live
case unknown = ""
static func convert(from string: String) -> AssetType {
return AssetType(rawValue: string) ?? .unknown
}
}
// Conforms AssetType to AssetTypeConvertible protocol, so that it can be decoded in SearchItem decode
extension AssetType: AssetTypeConvertible {
static func convertToEnum(from rawValue: String) -> AssetType {
return .convert(from: rawValue)
}
}
// Codable usage
struct SearchItem: Codable {
// MARK: - Properties
let assetType: AssetType
let id: String
let startDate: Date
let endDate: Date
// MARK: - Value Types
private enum CodingKeys: String, CodingKey {
case assetType = "AssetType"
case id = "ID"
case startDate, endDate
}
required init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
assetType = try container.decodeEnumFromRawValue(try container.decode(String.self, forKey: .assetType))
id = try container.decode(String.self, forKey: .id)
startDate = try Utilities.decodeDate(key: .startDate, in: container, using: .searchDateFormatter)
endDate = try Utilities.decodeDate(key: .endDate, in: container, using: .searchDateFormatter)
}
}
// DateFormatter
extension DateFormatter {
static var searchDateFormatter: DateFormatter {
// 5/16/2019 11:55:00 AM
let formatter = self.posixFormatter
formatter.dateFormat = "MM/dd/yyyy h:mm:ss a"
return formatter
}
static var posixFormatter: DateFormatter {
// https://developer.apple.com/library/archive/qa/qa1480/_index.html
let formatter = DateFormatter()
formatter.locale = Locale(identifier: "en_US_POSIX")
return formatter
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment