Simple RSS Reader

Run Settings
LanguageSwift
Language Version
Run Command
import Foundation class FeedParser: NSObject, XMLParserDelegate { fileprivate var rssItems = [(title: String, description: String, pubDate: String)]() fileprivate var currentElement = "" fileprivate var currentTitle = "" { didSet { currentTitle = currentTitle.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines) } } fileprivate var currentDescription = "" { didSet { currentDescription = currentDescription.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines) } } fileprivate var currentPubDate = "" { didSet { currentPubDate = currentPubDate.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines) } } fileprivate var parserCompletionHandler: (([(title: String, description: String, pubDate: String)]) -> Void)? func parseFeed(feedURL: String, completionHandler: (([(title: String, description: String, pubDate: String)]) -> Void)?) -> Void { parserCompletionHandler = completionHandler guard let feedURL = URL(string:feedURL) else { print("feed URL is invalid") return } URLSession.shared.dataTask(with: feedURL, completionHandler: { data, response, error in // ⚠️ TODO:: PARSE XML from data }).resume() } // MARK: - XMLParser Delegate func parserDidStartDocument(_ parser: XMLParser) { rssItems.removeAll() } func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String] = [:]) { currentElement = elementName if currentElement == "item" { currentTitle = "" currentDescription = "" currentPubDate = "" } } func parser(_ parser: XMLParser, foundCharacters string: String) { /// Note: current string may only contain part of info. // ⚠️ TODO:: Update current Title, Description and PubDate based on CurrentElement } func parser(_ parser: XMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) { if elementName == "item" { let rssItem = (title: currentTitle, description: currentDescription, pubDate: currentPubDate) rssItems.append(rssItem) } } func parserDidEndDocument(_ parser: XMLParser) { parserCompletionHandler?(rssItems) } func parser(_ parser: XMLParser, parseErrorOccurred parseError: Error) { print(parseError.localizedDescription) } }
import UIKit class NewsTableViewController: UITableViewController { fileprivate let feedParser = FeedParser() fileprivate let feedURL = "http://www.apple.com/main/rss/hotnews/hotnews.rss" fileprivate var rssItems: [(title: String, description: String, pubDate: String)]? fileprivate var cellStates: [CellState]? override func viewDidLoad() { super.viewDidLoad() tableView.estimatedRowHeight = 140 tableView.rowHeight = UITableView.automaticDimension tableView.separatorStyle = UITableViewCell.SeparatorStyle.singleLine feedParser.parseFeed(feedURL: feedURL) { [weak self] rssItems in self?.rssItems = rssItems self?.cellStates = Array(repeating: .collapsed, count: rssItems.count) DispatchQueue.main.async { self?.tableView.reloadSections(IndexSet(integer: 0), with: .none) } } } // MARK: - Table view data source override func numberOfSections(in tableView: UITableView) -> Int { return 1 } override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { guard let rssItems = rssItems else { return 0 } return rssItems.count } override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { // ⚠️ TODO:: using rssItems and NewsTableViewCell, fill out each cell's title, description, and date let cell = UITableViewCell() return cell } // MARK: - Table view delegate override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { tableView.deselectRow(at: indexPath, animated: true) if let cell = tableView.cellForRow(at: indexPath) as? NewsTableViewCell { // ⚠️ TODO:: Toggle cellStates between .collapsed and .expanded // ⚠️ TODO:: Toggle cell.descriptionLabel.numberOfLines between 0 and 4 // ⚠️ TODO:: Syncronize tableView update } } }
Editor Settings
Theme
Key bindings
Full width
Lines