DI seguito ecco il codice delle due classi che uso:
Questa gestisce l'elenco caricato dal feed:
ListViewController.swift
//
// ListViewController.swift
// SwiftRSSReader
//
// Created by Prashant on 14/09/15.
// Copyright (c) 2015 PrashantKumar Mangukiya. All rights reserved.
//
import UIKit
class ListViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, XMLParserDelegate {
// outlet - table view
@IBOutlet var myTableView: UITableView!
// outet - activity indicator
@IBOutlet var spinner: UIActivityIndicatorView!
// xml parser
var myParser: XMLParser = XMLParser()
// rss records
var rssRecordList : [RssRecord] = [RssRecord]()
var rssRecord : RssRecord?
var isTagFound = [ "item": false , "title":false, "pubDate": false ,"link":false]
// MARK - View functions
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
// set tableview delegate
self.myTableView.dataSource = self
self.myTableView.delegate = self
}
override func viewDidAppear(_ animated: Bool) {
// load Rss data and parse
if self.rssRecordList.isEmpty {
self.loadRSSData()
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Table view dataSource and Delegate
// return number of section within a table
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
// return row height
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 60
}
// return how may records in a table
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.rssRecordList.count
}
// return cell
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// collect reusable cell
let cell = tableView.dequeueReusableCell(withIdentifier: "rssCell", for: indexPath)
// find record for current cell
let thisRecord : RssRecord = self.rssRecordList[indexPath.row]
// set value for main title and detail tect
cell.textLabel?.text = thisRecord.title
cell.detailTextLabel?.text = thisRecord.pubDate
// return cell
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
self.performSegue(withIdentifier: "segueShowDetails", sender: self)
}
// MARK: - NSXML Parse delegate function
// start parsing document
func parserDidStartDocument(_ parser: XMLParser) {
// start parsing
}
// element start detected
func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String]) {
if elementName == "item" {
self.isTagFound["item"] = true
self.rssRecord = RssRecord()
}else if elementName == "title" {
self.isTagFound["title"] = true
}else if elementName == "link" {
self.isTagFound["link"] = true
}else if elementName == "pubDate" {
self.isTagFound["pubDate"] = true
}
}
// characters received for some element
func parser(_ parser: XMLParser, foundCharacters string: String) {
if isTagFound["title"] == true {
self.rssRecord?.title += string
}else if isTagFound["link"] == true {
self.rssRecord?.link += string
}else if isTagFound["pubDate"] == true {
self.rssRecord?.pubDate += string
}
}
// element end detected
func parser(_ parser: XMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) {
if elementName == "item" {
self.isTagFound["item"] = false
self.rssRecordList.append(self.rssRecord!)
}else if elementName == "title" {
self.isTagFound["title"] = false
}else if elementName == "link" {
self.isTagFound["link"] = false
}else if elementName == "pubDate" {
self.isTagFound["pubDate"] = false
}
}
// end parsing document
func parserDidEndDocument(_ parser: XMLParser) {
//reload table view
self.myTableView.reloadData()
// stop spinner
self.spinner.stopAnimating()
}
// if any error detected while parsing.
func parser(_ parser: XMLParser, parseErrorOccurred parseError: Error) {
// stop animation
self.spinner.stopAnimating()
// show error message
self.showAlertMessage(alertTitle: "Error", alertMessage: "Error while parsing xml.")
}
// MARK: - Utility functions
// load rss and parse it
fileprivate func loadRSSData(){
if let rssURL = URL(string: RSS_FEED_URL) {
// start spinner
self.spinner.startAnimating()
// fetch rss content from url
self.myParser = XMLParser(contentsOf: rssURL)!
// set parser delegate
self.myParser.delegate = self
self.myParser.shouldResolveExternalEntities = false
// start parsing
self.myParser.parse()
}
}
// show alert with ok button
fileprivate func showAlertMessage(alertTitle: String, alertMessage: String ) -> Void {
// create alert controller
let alertCtrl = UIAlertController(title: alertTitle, message: alertMessage, preferredStyle: UIAlertControllerStyle.alert) as UIAlertController
// create action
let okAction = UIAlertAction(title: "Ok", style: UIAlertActionStyle.default, handler:
{ (action: UIAlertAction) -> Void in
// you can add code here if needed
})
// add ok action
alertCtrl.addAction(okAction)
// present alert
self.present(alertCtrl, animated: true, completion: { (void) -> Void in
// you can add code here if needed
})
}
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
if segue.identifier == "segueShowDetails" {
// find index path for selected row
let selectedIndexPath : [IndexPath] = self.myTableView.indexPathsForSelectedRows!
// deselect the selected row
self.myTableView.deselectRow(at: selectedIndexPath[0], animated: true)
// create destination view controller
let destVc = segue.destination as! DetailsViewController
// set title for next screen
destVc.navigationItem.title = self.rssRecordList[selectedIndexPath[0].row].title
// set link value for destination view controller
destVc.link = self.rssRecordList[selectedIndexPath[0].row].link
}
}
}