Skip to content

Instantly share code, notes, and snippets.

@aligungor
Forked from romanroibu/RSSFeed.swift
Created December 6, 2018 13:40
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 aligungor/5774ec18b74af7330267e08fcdeb2e55 to your computer and use it in GitHub Desktop.
Save aligungor/5774ec18b74af7330267e08fcdeb2e55 to your computer and use it in GitHub Desktop.
Swift Decodable With Multiple Custom Dates (https://useyourloaf.com/blog/swift-codable-with-custom-dates)
import Foundation
extension DateFormatter {
static let iso8601Full: DateFormatter = {
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ"
formatter.calendar = Calendar(identifier: .iso8601)
formatter.timeZone = TimeZone(secondsFromGMT: 0)
formatter.locale = Locale(identifier: "en_US_POSIX")
return formatter
}()
static let yyyyMMdd: DateFormatter = {
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd"
formatter.calendar = Calendar(identifier: .iso8601)
formatter.timeZone = TimeZone(secondsFromGMT: 0)
formatter.locale = Locale(identifier: "en_US_POSIX")
return formatter
}()
}
public protocol FormattedDate: Codable {
static var formatter: DateFormatter { get }
var date: Date { get }
init(date: Date)
}
extension FormattedDate {
public init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
let string = try container.decode(String.self)
guard let date = Self.formatter.date(from: string) else {
let debug = "Date string does not match format expected by formatter."
throw DecodingError.dataCorruptedError(in: container, debugDescription: debug)
}
self.init(date: date)
}
public func encode(to encoder: Encoder) throws {
var container = encoder.singleValueContainer()
let string = Self.formatter.string(from: self.date)
try container.encode(string)
}
}
struct ISO8601Date: FormattedDate {
static let formatter: DateFormatter = .iso8601Full
let date: Date
}
struct YYYMMddDate: FormattedDate {
static var formatter: DateFormatter = .yyyyMMdd
let date: Date
}
public struct RSSFeed: Codable {
public struct Feed: Codable {
public struct Podcast: Codable {
public let name: String
public let artistName: String
public let url: URL
private let _releaseDate: YYYMMddDate
public var releaseDate: Date { return self._releaseDate.date }
private enum CodingKeys: String, CodingKey {
case name
case artistName
case url
case _releaseDate = "releaseDate"
}
}
public let title: String
public let country: String
private let _updated: ISO8601Date
public var updated: Date { return self._updated.date }
public let podcasts: [Podcast]
private enum CodingKeys: String, CodingKey {
case title
case country
case _updated = "updated"
case podcasts = "results"
}
}
public let feed: Feed
}
public typealias Feed = RSSFeed.Feed
public typealias Podcast = Feed.Podcast
let json = """
{
"feed": {
"title":"Top Audio Podcasts",
"country":"gb",
"updated":"2017-11-16T02:02:55.000-08:00",
"results":[
{
"artistName":"BBC Radio",
"name":"Blue Planet II: The Podcast",
"releaseDate":"2017-11-12",
"url":"https://itunes.apple.com/gb/podcast/blue-planet-ii-the-podcast/id1296222557?mt=2"
},
{
"artistName":"Audible",
"name":"The Butterfly Effect with Jon Ronson",
"releaseDate":"2017-11-03",
"url":"https://itunes.apple.com/gb/podcast/the-butterfly-effect-with-jon-ronson/id1258779354?mt=2"
},
{
"artistName":"TED",
"name":"TED Talks Daily",
"releaseDate":"2017-11-16",
"url":"https://itunes.apple.com/gb/podcast/ted-talks-daily/id160904630?mt=2"
}
]
}
}
"""
let data = Data(json.utf8)
let decoder = JSONDecoder()
let rssFeed = try! decoder.decode(RSSFeed.self, from: data)
let feed = rssFeed.feed
print(feed.title, feed.country, feed.updated)
feed.podcasts.forEach {
print($0.name)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment