I am trying to parse a xml file direct from a URL the code has no errors, and the app opens fine but the tableview is empty. here is the link and the code I have used, if I can get some guidance it would be greatly appreciated.
I initially built this through a tutorial (just learning the ropes)
import UIKit
class firecallViewController: UIViewController, NSXMLParserDelegate{
#IBOutlet var tbData: UITableView?
var parser = NSXMLParser()
var posts = NSMutableArray()
var elements = NSMutableDictionary()
var element = NSString()
var title1 = NSMutableString()
var date = NSMutableString()
override func viewDidLoad()
{
super.viewDidLoad()
self.beginParsing()
}
func beginParsing()
{
posts = []
parser = NSXMLParser(contentsOfURL:(NSURL(string:"https://example.com/bushfirealert/bushfireAlert.xml"))!)!
parser.delegate = self
parser.parse()
tbData!.reloadData()
}
//XMLParser Methods
func parser(parser: NSXMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String])
{
element = elementName
if (elementName as NSString).isEqualToString("item")
{
elements = NSMutableDictionary()
elements = [:]
title1 = NSMutableString()
title1 = ""
date = NSMutableString()
date = ""
}
}
func parser(parser: NSXMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?)
{
if (elementName as NSString).isEqualToString("item") {
if !title1.isEqual(nil) {
elements.setObject(title1, forKey: "title")
}
if !date.isEqual(nil) {
elements.setObject(date, forKey: "date")
}
posts.addObject(elements)
}
}
func parser(parser: NSXMLParser, foundCharacters string: String)
{
if element.isEqualToString("title") {
title1.appendString(string)
} else if element.isEqualToString("pubDate") {
date.appendString(string)
}
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
return posts.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
var cell : UITableViewCell = tableView.dequeueReusableCellWithIdentifier("Cell")!
if(cell.isEqual(NSNull)) {
cell = NSBundle.mainBundle().loadNibNamed("Cell", owner: self, options: nil)[0] as! UITableViewCell;
}
cell.textLabel?.text = posts.objectAtIndex(indexPath.row).valueForKey("title") as! NSString as String
cell.detailTextLabel?.text = posts.objectAtIndex(indexPath.row).valueForKey("date") as! NSString as String
return cell as UITableViewCell
}
}
Updated answer
You told me in the comments that you don't have to use NSXMLParser.
In this case, I have an easy solution for your parsing: use CheatyXML, a very simple library.
First, follow the easy install intructions.
Then make a parser with your URL:
import CheatyXML
let feedUrl = NSURL(string: "https://example.com/bushfirealert/bushfireAlert.xml")!
let parser = XMLParser(contentsOfURL: feedUrl)
And safely unwrap all values as if you were subscripting dictionaries, and use the .string property to get the string fields contents.
Like this:
if let parser = parser,
channel = parser["channel"],
title = channel["title"].string,
link = channel["link"].string,
description = channel["description"].string,
docs = channel["docs"].string,
generator = channel["generator"].string {
print(title)
print(link)
print(description)
print(docs)
print(generator)
}
Result:
QFES Current Incidents
http://bneags01.desqld.internal/publicfeed/PublicRssFeed.aspx
QFES Current Incidents
http://www.rssboard.org/rss-specification
Argotic Syndication Framework
Now instead of my series of print you call a method of yours to populate your variables and then you reload the table view, and you're set.
Old answer
NSXMLParser works asynchronously, so when you reload your table in beginParsing(), the data is not parsed yet.
You need to reload the table when the parser has finished parsing.
Luckily, there's a callback for that.
Remove tbData!.reloadData() from beginParsing() and add this delegate method to your view controller instead:
func parserDidEndDocument(parser: NSXMLParser) {
tbData!.reloadData()
}
Related
I am new to Swift programming. I have 2 classes to parse RSS and show the datas. It's named ParseRSSFeed and DetailVC. But I can't see the datas in TableView when I want to parse.
But if I call methods of XMLParserDelegate in DetailVC, it works. Probably I did a mistake while calling the methods from another class.
My code is as below.
What did I overlook?
ParseRSSFeeds class to parse XML
import UIKit
class ParseRSSFeeds: XMLParser, XMLParserDelegate{
var parser = XMLParser()
var news = NSMutableArray()
var elements = NSMutableDictionary()
var element = NSString()
var header = NSMutableString()
var link = NSMutableString()
var desc = NSMutableString()
var date = NSMutableString()
func parseFromUrl(){
news = []
parser = XMLParser(contentsOf: NSURL(string: "https://www.wired.com/feed/rss")! as URL)!
parser.delegate = self
parser.parse()
}
func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String] = [:]) {
element = elementName as NSString
if (elementName as NSString) .isEqual(to: "item") {
elements = NSMutableDictionary()
elements = [:]
header = NSMutableString()
header = ""
link = NSMutableString()
link = ""
desc = NSMutableString()
desc = ""
date = NSMutableString()
date = ""
}
}
func parser(_ parser: XMLParser, foundCharacters string: String) {
if element .isEqual(to: "title"){
header.append(string)
}else if element .isEqual(to: "link"){
link.append(string)
}else if element .isEqual(to: "description"){
desc.append(string)
}else if element .isEqual(to: "pubDate") {
date.append(string)
}
}
func parser(_ parser: XMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) {
if (elementName as NSString) .isEqual(to: "item") {
if !header .isEqual(nil) {
elements.setObject(header, forKey: "title" as NSCopying)
}
if !link .isEqual(nil) {
elements.setObject(link, forKey: "link" as NSCopying)
}
if !desc .isEqual(nil) {
elements.setObject(desc, forKey: "description" as NSCopying)
}
if !date .isEqual(nil) {
elements.setObject(date, forKey: "pubDate" as NSCopying)
}
news.add(elements)
}
}
}
DetailVC (It includes table view to show RSS feeds.)
import UIKit
class DetailVC: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var tblNews: UITableView!
let parser = ParseRSSFeeds()
override func viewDidLoad() {
super.viewDidLoad()
ParseRSSFeeds().parseFromUrl()
tblNews.reloadData()
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return parser.news.count - parser.news.count + 5
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell = tblNews.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
if cell .isEqual(NSNull.self) {
cell = Bundle.main.loadNibNamed("cell", owner: self, options: nil)?[0] as! UITableViewCell
}
cell.textLabel?.text = (parser.news.object(at: indexPath.row) as AnyObject).value!(forKey: "title") as? String
cell.detailTextLabel?.text = (parser.news.object(at: indexPath.row) as AnyObject).value!(forKey: "description") as? String
return cell
}
}
You have two ParseRSSFeeds instances, the parser property and the one you create in viewDidLoad. So, viewDidLoad is creating a second instance of ParseRSSFeeds, requesting and parsing the response, and then discarding those results, leaving the separate parser property untouched.
You should instead have viewDidLoad reference the parser property rather than creating new instance of ParseRSSFeeds:
override func viewDidLoad() {
super.viewDidLoad()
parser.parseFromUrl()
...
}
import UIKit
var operationViewFlag: Int!
var dataReceived: Int!
class HomeCellView: UITableViewCell
{
#IBOutlet weak var btn_tablecell_Delete: UIButton!
#IBOutlet weak var btn_tablecell_Edit: UIButton!
#IBOutlet weak var lbl_tablecell_Email: UILabel!
}
class ViewController: UIViewController,UITableViewDataSource,UITableViewDelegate, NSXMLParserDelegate
{
#IBOutlet weak var TableView_Mainscreen: UITableView!
#IBOutlet weak var lbl_MainScreen_Title: UILabel!
#IBOutlet weak var btn_Mainscreen_Insert: UIButton!
var databasepath:String!
var arrayStudInfo:NSMutableArray!
// for only xml parsing
var parser = NSXMLParser()
var posts = NSMutableArray()
var elements = NSMutableDictionary()
var element = NSString()
var title1 = NSMutableString()
var date = NSMutableString()
// viewDidLoad
override func viewDidLoad()
{
super.viewDidLoad()
arrayStudInfo = NSMutableArray()
self.beginParsing();
TableView_Mainscreen.reloadData()
}
//viewWillAppear
override func viewWillAppear(animated: Bool)
{
super.viewWillAppear(true)
TableView_Mainscreen.reloadData()
}
override func didReceiveMemoryWarning()
{
super.didReceiveMemoryWarning()
}
// TableView Methods
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
print("Number Of Row:\(posts.count)")
return posts.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
let Cell = tableView.dequeueReusableCellWithIdentifier("CellHome") as! HomeCellView
print("Index path - > \(posts[indexPath.row])")
Cell.lbl_tablecell_Email.text! = String("\(posts[(indexPath.row)]["title"])")
return Cell
}
func parser(parser: NSXMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String])
{
element = elementName
print("element Name : - \(elementName)")
if (elementName as NSString).isEqualToString("item")
{
elements = NSMutableDictionary()
elements = [:]
title1 = NSMutableString()
title1 = ""
date = NSMutableString()
date = ""
}
}
func parser(parser: NSXMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?)
{
print("element Name : - \(elementName)")
if (elementName as NSString).isEqualToString("item")
{
if !title1.isEqual(nil) {
elements.setObject(title1, forKey: "Name")
}
if !date.isEqual(nil) {
elements.setObject(date, forKey: "Level")
}
posts.addObject(elements)
}
}
func parser(parser: NSXMLParser, foundCharacters string: String)
{
if element.isEqualToString("Name")
{
title1.appendString(string)
} else if element.isEqualToString("Level") {
date.appendString(string)
}
}
func beginParsing()
{
posts = []
parser = NSXMLParser(contentsOfURL:(NSURL(string:"http://d1xzuxjlafny7l.cloudfront.net/downloads/Party.xml"))!)!
parser.delegate = self
parser.parse()
}
func parserDidEndDocument(parser: NSXMLParser) {
TableView_Mainscreen.reloadData()
}
}
I want to display the result of the xml api in proper formate. I want to display the name from it, in table view. Right now i am not getting any data from this. First of all If will get any data then and then we can think to convert or arrange in any formate , but i am not getting any thing. will anybody please help for the same.
Edit:
Oh! I didn't check your XML thoroughly enough! In fact, it has nothing to do with the parser loading the data asynchronously (I'll leave my original hint regarding parserDidEndDocument below, though, you might need it once you implement a refresh feature).
Turns out you simply did not use the correct names, i.e. strings for the elements. Here's the corrected code:
In tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell (note I slightly changed how to get the string, otherwise you might get an ugly prefix in it)
...
let nameString = posts[(indexPath.row)]["Name"] as! String
Cell.lbl_tablecell_Email.text = nameString
...
In parser(parser: NSXMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String])
...
if (elementName as NSString).isEqualToString("Player")
...
In parser(parser: NSXMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?)
...
if (elementName as NSString).isEqualToString("Player")
...
In parser(parser: NSXMLParser, foundCharacters string: String) (note you seem to have a linebreak and some whitespaces in your XML, I cut that off)
...
if element.isEqualToString("Name") && !(string.hasPrefix("\n"))
...
I assume you didn't realize those string keys that identify the elements are actually just the element's name, basically. There's a couple of small things in your code that could be optimized and/or improved (for example you don't need to initialize some vars, since you just re-init them elsewhere before actual usage anyways, also the naming of variables).
I tried it out with the link you provided and it works now.
Gist of previous answer:
Implement
func parserDidEndDocument(parser: NSXMLParser) {
TableView_Mainscreen.reloadData()
}
so that you are guaranteed to reload the table's data after the parser is done parsing.
During my app development I've encountered a specific problem.
I've a database which contains following columns: Dossier_Title, Dossier_Name, Dossier_Category and Dossier_Description. The Description is uniqe for every Dossier.
First of all I'm calling my WebService which selects unique Dossier_Title and forms an xml page. After that app parse this page and forms a number of unique cells in table View. Also it forms an array which consists of Dossier_Title and Dossier_category.
Now I want to form a new tableView which would consist of Dossier_Name and Dossier_Description based on the Dossier_Category I've achieved on previous step. For this I want to call a new WebService and parse it using that Category as condition.
My question is: how can I pass Dossier_category to my second parser so I can use it as condition?
Here is my first parser code I assume the second one would be pretty much the same with addition of some new conditions
class DossierParser: NSObject, NSXMLParserDelegate {
var parser = NSXMLParser()
var feeds = NSMutableArray()
var elements = NSMutableDictionary()
var element = NSString()
var ftitle = NSMutableString()
var link = NSMutableString()
var fdescription = NSMutableString()
var fdate = NSMutableString()
var fcategory = NSMutableString()
// initilise parser
/*
func initWithURL(url :NSURL) -> AnyObject {
startParse(url)
return self
}
*/
init(URL: NSURL){
super.init()
startParse(URL)
}
func startParse(url :NSURL) {
feeds = []
parser = NSXMLParser(contentsOfURL: url)!
parser.delegate = self
parser.shouldProcessNamespaces = false
parser.shouldReportNamespacePrefixes = false
parser.shouldResolveExternalEntities = false
parser.parse()
}
func allFeeds() -> NSMutableArray {
return feeds
}
func parser(parser: NSXMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String]) {
self.element = elementName
if self.element == "News" {
elements = NSMutableDictionary()
elements = [:]
ftitle = NSMutableString()
ftitle = ""
fdescription = NSMutableString()
fdescription = ""
fdate = NSMutableString()
fdate = ""
fcategory = NSMutableString()
fcategory = ""
}
}
func parser(parser: NSXMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) {
if (elementName as NSString).isEqualToString("News") {
if ftitle != "" {
elements.setObject(ftitle, forKey: "DosNum")
}
if fcategory != "" {
elements.setObject(fcategory, forKey: "Dossier_number")
}
if fdate != "" {
elements.setObject(fdate, forKey: "Date_Text")
}
feeds.addObject(elements)
}
}
func parser(parser: NSXMLParser, foundCharacters string: String?) {
if element.isEqualToString("DosNum") {
ftitle.appendString(string!)
}else if element.isEqualToString("Date_Text") {
fdate.appendString(string!)
}else if element.isEqualToString("Dossier_number"){
fcategory.appendString(string!)
}
}
And here is my first TableView code.
var myFeed : NSArray = []
var url: NSURL = NSURL()
override func viewDidLoad() {
super.viewDidLoad()
// Cell height.
self.tableView.rowHeight = 70
self.tableView.dataSource = self
self.tableView.delegate = self
//url = NSURL(string: "https://www.kpmg.com/_layouts/feed.aspx?xsl=1&web=/RU/ru/IssuesAndInsights/RSSFeeds&page=207b36b2-20f7-407f-a9ec-a09f191fd84b&wp=9810a349-6086-489d-ad03-40c06f6669f6")!
//url = NSURL(string: "http://www.skysports.com/rss/0,20514,11661,00.xml")!
// url = NSURL(scheme: "https", host: "www.kpmg.com", path: "/_layouts/feed.aspx?xsl=1&web=/RU/ru/IssuesAndInsights/RSSFeeds&page=207b36b2-20f7-407f-a9ec-a09f191fd84b&wp=9810a349-6086-489d-ad03-40c06f6669f6")!
//(scheme: "http", host: "10.207.203.216", path: "/AppWebservice/Service1.asmx/getNewsData")!
url = NSURL(string: "http://10.207.206.74/AppWebservice/Service1.asmx/getUniqDossier")!
// Call custom function.
loadRss(url);
}
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
self.navigationItem.title = ""
let backImg:UIImage! = UIImage(named: "backPicture.png")
self.navigationItem.backBarButtonItem =
UIBarButtonItem(image:backImg, style:.Plain, target:self, action:nil);
let navBgImage:UIImage = UIImage(named: "express.png")!
self.navigationController?.navigationBar.setBackgroundImage(navBgImage, forBarMetrics: .Default)
}
func loadRss(data: NSURL) {
let myParser = DossierParser(URL: data)
myFeed = myParser.feeds
tableView.reloadData()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "openPage" {
let indexPath: NSIndexPath = self.tableView.indexPathForSelectedRow!
let selectedFTitle: String = myFeed[indexPath.row].objectForKey("DosNum") as! String
let selectedFContent: String = myFeed[indexPath.row].objectForKey("Dossier_number") as! String
// Instance of our feedpageviewcontrolelr
let fpvc: FeedPageViewController = segue.destinationViewController as! FeedPageViewController
fpvc.selectedFeedTitle = selectedFTitle
fpvc.selectedFeedFeedContent = selectedFContent
}
}
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return myFeed.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath)
let chevron = UIImage(named: "Next4.png")
cell.accessoryType = .DisclosureIndicator
cell.accessoryView = UIImageView(image: chevron!)
cell.textLabel?.textColor = UIColor.blackColor()
// Feeds dictionary.
var dict : NSDictionary! = myFeed.objectAtIndex(indexPath.row) as! NSDictionary
// Set cell properties.
cell.textLabel?.text = myFeed.objectAtIndex(indexPath.row).objectForKey("DosNum") as? String
cell.detailTextLabel?.text = myFeed.objectAtIndex(indexPath.row).objectForKey("Date_text") as? String
return cell
}
I would appreciate any sort of help. My guessing there should be easier way around it, but I don't know it, so if someone has suggestion it would be nice!
Thanks!
I believe you would want to retain an instance of fCategory and pass it to the second parser class via init.
The second parser class should have the following to allow for the fcategory to be passed in and stored locally for use by the parser.
let fcategory = NSMutableString()
let URL = NSURL
init(URL: NSURL, category: String){
super.init()
self.URL = URL
self.fcategory = category
self.startParse(URL, fcategory)
}
I have a web service which give xml response. I want to parse and show in table. But my XMLParser delegate not called. I am newer in swift. Please help any help would be apperciated,
class ViewController: UIViewController,NSXMLParserDelegate,UITableViewDelegate {
var element:String?
var titles:NSMutableString?
var link:NSMutableString?
var tableData:NSMutableArray?
var dict:NSMutableDictionary?
#IBOutlet weak var table: UITableView?
override func viewDidLoad() {
super.viewDidLoad()
dict = NSMutableDictionary()
tableData = NSMutableArray()
let url = NSURL(string: "hp?keytext=s")
let theRequest = NSURLRequest(URL: url)
NSURLConnection.sendAsynchronousRequest(theRequest, queue: nil, completionHandler: {(response: NSURLResponse!, data: NSData!, error: NSError!) -> Void in
if data.length > 0 && error == nil {
//var parser=NSXMLParser(data: data)
var parser = NSXMLParser(contentsOfURL: url)
parser.delegate=self
parser.shouldResolveExternalEntities=false
parser.parse()
}
})
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func tableView(tableView: UITableView?, numberOfRowsInSection section: Int) -> Int {
// Return the number of rows in the section.
return tableData!.count
}
func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell! {
var cell = tableView.dequeueReusableCellWithIdentifier("CELL") as? UITableViewCell
if !(cell != nil) {
cell = UITableViewCell(style: UITableViewCellStyle.Value1, reuseIdentifier: "CELL")}
var a:NSString
var b:String
a = tableData?.objectAtIndex(indexPath.row).objectForKey("title") as NSString
b = tableData?.objectAtIndex(indexPath.row).objectForKey("city") as NSString
cell?.textLabel?.text=a;
cell?.detailTextLabel?.text=b
return cell
}
func tableView(tableView:UITableView, heightForRowAtIndexPath indexPath:NSIndexPath)->CGFloat
{
return 78;
}
func parser(parser: NSXMLParser, didStartElement elementName: String, namespaceURI: String, qualifiedName qName: String, attributes attributeDict: [NSObject : AnyObject]) {
element=elementName
if element=="restaurant"
{
titles=NSMutableString()
link=NSMutableString()
}
}
func parser(parser: NSXMLParser, foundCharacters string: String) {
if element=="title"
{
titles?.appendString(string)
}
else if element=="city"
{
link!.appendString(string)
}
}
func parser(parser: NSXMLParser, didEndElement elementName: String, namespaceURI: String, qualifiedName qName: String) {
if elementName == "restaurant"
{
dict?.setValue(titles, forKeyPath: "title")
dict?.setValue(link, forKeyPath: "city")
tableData?.addObject(dict!)
}
}
func parserDidEndDocument(parser: NSXMLParser!){
table?.reloadData()
}
}
You don't need to use sendAsynchronousRequest in your viewDidLoad method instead of that use this code:
Declare parser variable outside of all function.
Then in your viewDidLoad method replace your code with this code:
override func viewDidLoad() {
super.viewDidLoad()
let url = NSURL(string: "http://images.apple.com/main/rss/hotnews/hotnews.rss") //this is example URL
parser = NSXMLParser(contentsOfURL: url)!
parser.delegate = self
parser.parse()
}
And your full code will be:
import UIKit
class ViewController: UIViewController,NSXMLParserDelegate,UITableViewDelegate, UITableViewDataSource { //You will need UITableViewDataSource here.
var parser : NSXMLParser = NSXMLParser()
var element:String?
var titles:NSMutableString?
var link:NSMutableString?
var tableData:NSMutableArray?
var dict:NSMutableDictionary?
#IBOutlet weak var table: UITableView?
override func viewDidLoad() {
super.viewDidLoad()
let url = NSURL(string: "http://images.apple.com/main/rss/hotnews/hotnews.rss")
parser = NSXMLParser(contentsOfURL: url)!
parser.delegate = self
parser.parse()
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// Return the number of rows in the section.
return tableData!.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCellWithIdentifier("CELL") as? UITableViewCell
if !(cell != nil) {
cell = UITableViewCell(style: UITableViewCellStyle.Value1, reuseIdentifier: "CELL")}
var a:NSString
var b:String
a = tableData?.objectAtIndex(indexPath.row).objectForKey("title") as! NSString
b = tableData?.objectAtIndex(indexPath.row).objectForKey("city") as! NSString as String
cell?.textLabel?.text = a as String;
cell?.detailTextLabel?.text = b
return cell!
}
func tableView(tableView:UITableView, heightForRowAtIndexPath indexPath:NSIndexPath)->CGFloat
{
return 78;
}
func parser(parser: NSXMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [NSObject : AnyObject]) {
element=elementName
if element=="restaurant"
{
titles=NSMutableString()
link=NSMutableString()
}
}
func parser(parser: NSXMLParser, foundCharacters string: String?) {
if element=="title"
{
titles?.appendString(string!)
}
else if element=="city"
{
link!.appendString(string!)
}
}
func parser(parser: NSXMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) {
if elementName == "restaurant"
{
dict?.setValue(titles, forKeyPath: "title")
dict?.setValue(link, forKeyPath: "city")
tableData?.addObject(dict!)
}
}
func parserDidEndDocument(parser: NSXMLParser){
table?.reloadData()
}
}
I have updated your delegate functions too.
And check that you are getting data from your URL or not.
And I suggest you to follow THIS tutorial first which will help you to understand everything.
First thing your url is not valid url, you are passing only this string as a URL "hp?keytext=s".
Second thing put this method it will call when your parse fail.
func parser(parser: NSXMLParser, parseErrorOccurred parseError: NSError) {
NSLog("failure error: %#", parseError)
}
I am totally new to SWIFT and to developing in general. I am currently building an RSS news feed to hone my (very limited) skills. I am basically parsing an RSS feed from a random news channel and then storing the titles in a simple table view.
I am trying to implement UIPullToRefresh using SWIFT, and truth be told I am kinda stuck! I have written the following code. As you can see I have added the necessary code to my viewDidLoad method. At this point the refresh spinner works well but I am now wondering what code is needed in my "refresh function" to actually refresh my table view.
I know this may seem trivial to most of you guys, but i am fairly new to this and i have been pulling my hair for the last 12 hours ... so anything would probably help at this point.
Thanks for your help!
import UIKit
class BRTableViewController: UITableViewController, NSXMLParserDelegate {
var parser: NSXMLParser = NSXMLParser()
var blogPosts: [BlogPost] = []
var postTitle: String = String()
var postLink: String = String()
var postDate: String = String()
var eName: String = String()
override func viewDidLoad() {
super.viewDidLoad()
let url:NSURL = NSURL(string: "http://rt.com/rss/")!
parser = NSXMLParser(contentsOfURL: url)!
parser.delegate = self
parser.parse()
// pull to refresh the table view
refreshControl!.attributedTitle = NSAttributedString(string: "Pull to refresh")
refreshControl!.addTarget(self, action: "refresh:", forControlEvents: UIControlEvents.ValueChanged)
tableView.addSubview(refreshControl!)
}
func refresh(sender:AnyObject){
let url:NSURL = NSURL(string: "http://rt.com/rss/")!
parser = NSXMLParser(contentsOfURL: url)!
parser.delegate = self
parser.parse()
}
// MARK: - NSXMLParserDelegate methods
func parser(parser: NSXMLParser!, didStartElement elementName: String!, namespaceURI: String!, qualifiedName qName: String!, attributes attributeDict: [NSObject : AnyObject]!) {
eName = elementName
if elementName == "item" {
postTitle = String()
postLink = String()
postDate = String()
}
}
func parser(parser: NSXMLParser!, foundCharacters string: String!) {
let data = string.stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceAndNewlineCharacterSet())
if (!data.isEmpty) {
if eName == "title" {
postTitle += data
} else if eName == "link" {
postLink += data
} else if eName == "pubDate" {
postDate += data
}
}
}
func parser(parser: NSXMLParser!, didEndElement elementName: String!, namespaceURI: String!, qualifiedName qName: String!) {
if elementName == "item" {
let blogPost: BlogPost = BlogPost()
blogPost.postTitle = postTitle
blogPost.postLink = postLink
blogPost.postDate = postDate
blogPosts.append(blogPost)
}
}
override func parser(parser: NSXMLParser!, didEndElement elementName: String!, namespaceURI: String!, qualifiedName qName: String!) {
if elementName == "item" {
self.tableView.reloadData();
self.refreshControl.endRefreshing();
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return blogPosts.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as UITableViewCell
let blogPost: BlogPost = blogPosts[indexPath.row]
cell.textLabel.text = blogPost.postTitle
cell.detailTextLabel?.text = blogPost.postDate.substringToIndex(advance(blogPost.postDate.startIndex, 25))
return cell
}
override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return 50.0
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if segue.identifier == "viewpost" {
let selectedRow = tableView.indexPathForSelectedRow()?.row
let blogPost: BlogPost = blogPosts[selectedRow!]
let viewController = segue.destinationViewController as PostViewController
viewController.postLink = blogPost.postLink
}
}
}
I think this fix the issue:
func refresh(sender:AnyObject){
parser = NSXMLParser(contentsOfURL: url)!
parser.delegate = self
parser.parse()
}
This will re-parse the XML and update the blogPosts variable.
Remove the following line in viewDidLoad:
refreshControl = UIRefreshControl()
You should also override the parserDidEndDocument function to include this:
func parserDidEndDocument(parser: NSXMLParser!){
self.tableView.reloadData();
self.refreshControl?.endRefreshing();
}
This will refresh the table view once the parser is done.