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
  • Select an option

  • Save romanroibu/089ec641757604bf78a390654c437cb0 to your computer and use it in GitHub Desktop.

Select an option

Save romanroibu/089ec641757604bf78a390654c437cb0 to your computer and use it in GitHub Desktop.

Revisions

  1. romanroibu revised this gist Dec 26, 2017. No changes.
  2. romanroibu revised this gist Dec 11, 2017. 1 changed file with 57 additions and 25 deletions.
    82 changes: 57 additions & 25 deletions RSSFeed.swift
    Original file line number Diff line number Diff line change
    @@ -9,7 +9,7 @@ extension DateFormatter {
    formatter.locale = Locale(identifier: "en_US_POSIX")
    return formatter
    }()

    static let yyyyMMdd: DateFormatter = {
    let formatter = DateFormatter()
    formatter.dateFormat = "yyyy-MM-dd"
    @@ -20,50 +20,83 @@ extension DateFormatter {
    }()
    }

    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
    public let releaseDate: Date

    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
    public let updated: Date

    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
    case _updated = "updated"
    case podcasts = "results"
    }
    }

    public let feed: Feed
    }

    public typealias Feed = RSSFeed.Feed
    public typealias Podcast = Feed.Podcast

    extension Podcast {
    public init(from decoder: Decoder) throws {
    let container = try decoder.container(keyedBy: CodingKeys.self)
    name = try container.decode(String.self, forKey: .name)
    artistName = try container.decode(String.self, forKey: .artistName)
    url = try container.decode(URL.self, forKey: .url)
    let dateString = try container.decode(String.self, forKey: .releaseDate)
    let formatter = DateFormatter.yyyyMMdd
    if let date = formatter.date(from: dateString) {
    releaseDate = date
    } else {
    throw DecodingError.dataCorruptedError(forKey: .releaseDate, in: container, debugDescription: "Date string does not match format expected by formatter.")
    }
    }
    }

    let json = """
    {
    "feed": {
    @@ -96,12 +129,11 @@ let json = """

    let data = Data(json.utf8)
    let decoder = JSONDecoder()
    decoder.dateDecodingStrategy = .formatted(DateFormatter.iso8601Full)
    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)
    }
    }
  3. @kharrison kharrison revised this gist Nov 20, 2017. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions RSSFeed.swift
    Original file line number Diff line number Diff line change
    @@ -45,8 +45,8 @@ public struct RSSFeed: Codable {
    public let feed: Feed
    }

    typealias Feed = RSSFeed.Feed
    typealias Podcast = Feed.Podcast
    public typealias Feed = RSSFeed.Feed
    public typealias Podcast = Feed.Podcast

    extension Podcast {
    public init(from decoder: Decoder) throws {
  4. @kharrison kharrison revised this gist Nov 20, 2017. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion RSSFeed.swift
    Original file line number Diff line number Diff line change
    @@ -29,7 +29,7 @@ public struct RSSFeed: Codable {
    public let releaseDate: Date
    }

    let title: String
    public let title: String
    public let country: String
    public let updated: Date
    public let podcasts: [Podcast]
  5. @kharrison kharrison created this gist Nov 20, 2017.
    107 changes: 107 additions & 0 deletions RSSFeed.swift
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,107 @@
    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 struct RSSFeed: Codable {
    public struct Feed: Codable {
    public struct Podcast: Codable {
    public let name: String
    public let artistName: String
    public let url: URL
    public let releaseDate: Date
    }

    let title: String
    public let country: String
    public let updated: Date
    public let podcasts: [Podcast]

    private enum CodingKeys: String, CodingKey {
    case title
    case country
    case updated
    case podcasts = "results"
    }
    }

    public let feed: Feed
    }

    typealias Feed = RSSFeed.Feed
    typealias Podcast = Feed.Podcast

    extension Podcast {
    public init(from decoder: Decoder) throws {
    let container = try decoder.container(keyedBy: CodingKeys.self)
    name = try container.decode(String.self, forKey: .name)
    artistName = try container.decode(String.self, forKey: .artistName)
    url = try container.decode(URL.self, forKey: .url)
    let dateString = try container.decode(String.self, forKey: .releaseDate)
    let formatter = DateFormatter.yyyyMMdd
    if let date = formatter.date(from: dateString) {
    releaseDate = date
    } else {
    throw DecodingError.dataCorruptedError(forKey: .releaseDate, in: container, debugDescription: "Date string does not match format expected by formatter.")
    }
    }
    }

    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()
    decoder.dateDecodingStrategy = .formatted(DateFormatter.iso8601Full)
    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)
    }