Skip to content

Instantly share code, notes, and snippets.

@romanroibu
Forked from kharrison/RSSFeed.swift
Last active April 9, 2021 15:28
Show Gist options
  • Star 6 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save romanroibu/089ec641757604bf78a390654c437cb0 to your computer and use it in GitHub Desktop.
Save romanroibu/089ec641757604bf78a390654c437cb0 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)
}
@ekilah
Copy link

ekilah commented Feb 21, 2019

nice, i like the changes from the blog post's version

@felipebweber
Copy link

felipebweber commented Mar 2, 2021

thanks, this code is awesome

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment