I'm thinking about check the internet connection and display a message if here is not connection, so now I have a TableView, And I think I have to delete or replace this table view or show only one cell and display a message like "There is no internet connection", so first I added a file to check connection so I did this:
override func viewDidLoad()
{
super.viewDidLoad()
self.navigationController?.navigationBar.barTintColor = UIColor(red: 38.0/255.0, green: 51.0/255.0, blue: 85.0/255.0, alpha: 1.0)
self.navigationController?.navigationBar.titleTextAttributes = [NSFontAttributeName: UIFont(name: "Gotham", size: 13)!, NSForegroundColorAttributeName : UIColor.whiteColor()]
self.title = "ACTUALITÉS"
if Reachability.isConnectedToNetwork() == true {
self.beginParsing()
} else {
//Here I'm gonna do something and display an image
}
}
#IBAction func menuTapped(sender: AnyObject) {
print(delegate)
delegate?.toggleLeftPanel?()
}
override func didReceiveMemoryWarning()
{
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func beginParsing()
{
posts = []
parser = NSXMLParser(contentsOfURL:(NSURL(string:"url..."))!)!
parser.delegate = self
parser.parse()
tableView!.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 = ""
dscrptn = NSMutableString()
dscrptn = ""
url = NSURL()
urlString = NSMutableString()
urlString = ""
} else {
title1 = NSMutableString()
title1 = "No connection"
}
}
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")
}
if !dscrptn.isEqual(nil) {
elements.setObject(dscrptn, forKey: "dscrptn")
}
if !urlString.isEqual(nil) {
elements.setObject(urlString, forKey: "urlString")
}
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)
} else if element.isEqualToString("description") {
dscrptn.appendString(string)
} else if element.isEqualToString("link") {
urlString.appendString(string)
}
}
//Tableview Methods
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
return posts.count
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let trimUrl = posts.objectAtIndex(indexPath.row).valueForKey("urlString") as! String
UIApplication.sharedApplication().openURL(NSURL(string: trimUrl.stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceAndNewlineCharacterSet()))!)
}
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
func tableView(tableView: UITableView, estimatedHeightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return 10
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
return basicCellAtIndexPath(indexPath)
}
func basicCellAtIndexPath(indexPath:NSIndexPath) -> ActuTblCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell") as! ActuTblCell
setTitleForCell(cell, indexPath: indexPath)
setDateForCell(cell, indexPath: indexPath)
setDescriptionForCell(cell, indexPath: indexPath)
return cell
}
func setTitleForCell(cell:ActuTblCell, indexPath:NSIndexPath) {
cell.titleActuCell?.text = posts.objectAtIndex(indexPath.row).valueForKey("title") as! NSString as String
}
func setDateForCell(cell:ActuTblCell, indexPath:NSIndexPath) {
let dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZ"
let dateString = posts.objectAtIndex(indexPath.row).valueForKey("date") as! NSString as String
if let dateAdded = dateFormatter.dateFromString(dateString.stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceAndNewlineCharacterSet()))
{
dateFormatter.dateFormat = "dd/MM/yyyy"
cell.dateActuCell?.text = "\(dateFormatter.stringFromDate(dateAdded))"
}
//cell.dateActuCell?.text = posts.objectAtIndex(indexPath.row).valueForKey("date") as! NSString as String
}
func setDescriptionForCell(cell:ActuTblCell, indexPath:NSIndexPath) {
cell.descriptionActuCell?.text = (posts.objectAtIndex(indexPath.row).valueForKey("dscrptn") as! NSString as String).stripHTML()
}
}
let htmlReplaceString : String = "<[^>]+>"
extension NSString {
func stripHTML() -> NSString {
return self.stringByReplacingOccurrencesOfString(htmlReplaceString, withString: "", options: NSStringCompareOptions.RegularExpressionSearch, range: NSRange(location: 0,length: self.length)) as NSString
}
}
extension String {
func stripHTML() -> String {
return self.stringByReplacingOccurrencesOfString(htmlReplaceString, withString: "", options: NSStringCompareOptions.RegularExpressionSearch, range: nil)
}
}
I know how to check connection but here I don't know what is the better solution and how to do it.
What you want to achieve it is called empty states. Ideas for empty states can be found www.pttrns.com. In your case empty state is shown when no network connection. Another case could be when network connection available, but post array have zero items after the parsing the content (XML/JSON).
I would recommend you to use 3rd party code:
DZNEmptyDataSet (objective-c)
StatefulViewController (Swfit)
Another way would be to set background image to the tableView. I want to notice that background image should be the size as device screen. You can do it like that:
let tempImageView = UIImageView(image: UIImage(named: "yourImage"))
tempImageView.frame = self.tableView.frame
self.tableView.backgroundView = tempImageView;
Related
I am making an simple news app, and trying to save (title, description, date, image with its data) in NSUserDefaults for offline read. I want when it save data in NSUserDefaults, it shows in offline and also when new data is available it rewrite or replace with previous data.
I know how to save string arrays in NSUserDefaults but did't know properly about how image saved in NSUserDefaults. I am trying to make logic of saving data and check it if new data is available but did't get success, also splash screen is take more time to disappear , is it due to loading data from server or due to slow internet connection?
Can anyone please check my code for fix it.
Thanks
class ViewController2: UIViewController ,NSXMLParserDelegate {
let newsDefaults = NSUserDefaults.standardUserDefaults()
#IBOutlet weak var tableView: UITableView!
var parser = NSXMLParser()
var posts = NSMutableArray()
var elements = NSMutableDictionary()
var element = NSString()
var title1 = NSMutableString()
var date = NSMutableString()
var link = NSMutableString()
var des = NSMutableString()
var img2 = NSMutableString()
var NSUserDefaultsTitle : [NSString] = []
var NSUserDefaultsDate : [NSString] = []
var NSUserDefaultsDes : [NSString] = []
var NSUserDefaultsImage : [UIImage] = []
typealias CompletionHandler = (image: UIImage) -> Void
var attrsUrl : [String : NSString]!
var urlPic : NSString?
var postLink: String = String()
override func viewDidLoad() {
super.viewDidLoad()
self.configure()
self.beginParsing()
}
override func viewWillAppear(animated: Bool) {
// if let HaveTitle = newsDefaults.objectForKey("t"){
// NSUserDefaultsTitle = HaveTitle.mutableCopy() as! [NSString]
// }
// if let HaveDate = newsDefaults.objectForKey("d"){
// NSUserDefaultsDate = HaveDate.mutableCopy() as! [NSString]
// }
// if let HaveDes = newsDefaults.objectForKey("des"){
// NSUserDefaultsDes = HaveDes.mutableCopy() as! [NSString]
// }
// if let imageData = newsDefaults.objectForKey("imgData"){
// NSUserDefaultsImage = imageData.mutableCopy() as! [UIImage]
// }
//
// print(newsDefaults.objectForKey("d"))
}
func beginParsing()
{
posts = []
parser = NSXMLParser(contentsOfURL:(NSURL(string: "http://www.voanews.com/api/zq$omekvi_"))!)!
parser.delegate = self
parser.parse()
tableView!.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 = ""
link = NSMutableString()
link = ""
des = NSMutableString()
des = ""
img2 = NSMutableString()
img2 = ""
}
if elementName == "enclosure" {
attrsUrl = attributeDict as [String: NSString]
urlPic = attrsUrl["url"]
print(urlPic!, terminator: "")
}
}
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: "pubDate")
}
if !link.isEqual(nil) {
elements.setObject(link, forKey: "link")
}
if !des.isEqual(nil){
elements.setObject(des, forKey: "description")
}
if !img2.isEqual(nil){
elements.setObject(urlPic!, forKey: "enclosure")
}
posts.addObject(elements)
//
// if let HaveData = newsDefaults.objectForKey("post"){
//
// }else{
//
//// newsDefaults.setObject(self.posts.valueForKey("title"), forKey: "t")
//// newsDefaults.setObject(self.posts.valueForKey("pubDate"), forKey: "d")
//// newsDefaults.setObject(self.posts.valueForKey("description"), forKey: "des")
//
// newsDefaults.setObject(posts, forKey: "post")
//
print("elementName")
// }
}
print("didEndElement")
}
func parser(parser: NSXMLParser, foundCharacters string: String)
{
if element.isEqualToString("title") {
title1.appendString(string)
} else if element.isEqualToString("pubDate") {
date.appendString(string)
print(date)
}
else if element.isEqualToString("link"){
link.appendString(string)
}else if element.isEqualToString("description"){
des.appendString(string)
}else if element.isEqualToString("enclosure"){
img2.appendString(string)
}
print("foundCharacter")
}
private func configure() {
self.navigationController?.navigationBar.titleTextAttributes = [NSFontAttributeName: UIFont.boldSystemFontOfSize(20.0), NSForegroundColorAttributeName: UIColor.whiteColor()]
self.tableView.registerNib(UINib(nibName: "2ImageCell", bundle: nil), forCellReuseIdentifier: "imageCell")
self.tableView.delegate = self
self.tableView.dataSource = self
self.fillNavigationBar(color: UIColor(red: 252.0/255.0, green: 0, blue: 0, alpha: 1.0))
}
private func fillNavigationBar(color color: UIColor) {
if let nav = self.navigationController {
nav.navigationBar.setBackgroundImage(UIImage(), forBarMetrics: .Default)
nav.navigationBar.shadowImage = UIImage()
for view in nav.navigationBar.subviews {
if view.isKindOfClass(NSClassFromString("_UINavigationBarBackground")!) {
if view.isKindOfClass(UIView) {
(view as UIView).backgroundColor = color
}
}
}
}
}
}
extension ViewController2: UITableViewDelegate, UITableViewDataSource {
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
self.tableView.deselectRowAtIndexPath(indexPath, animated: true)
let view = ImageModalView2.instantiateFromNib()
view.des.text = posts.objectAtIndex(indexPath.row).valueForKey("description") as? String
downloadFileFromURL(NSURL(string: self.posts.objectAtIndex(indexPath.row).valueForKey("enclosure") as! String)!, completionHandler:{(img) in
dispatch_async(dispatch_get_main_queue(), { () -> Void in
view.image = img
})
})
let window = UIApplication.sharedApplication().delegate?.window!
let modal = PathDynamicModal.show(modalView: view, inView: window!)
view.closeButtonHandler = {[weak modal] in
modal?.closeWithLeansRandom()
return
}
}
#IBAction func printData(sender: AnyObject) {
print(NSUserDefaultsImage)
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return 80.0
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return posts.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = self.tableView.dequeueReusableCellWithIdentifier("imageCell", forIndexPath: indexPath) as! ImageCell2
// if let picURL = user["picture"].string, url = NSURL(string: picURL) {
// if let data = NSData(contentsOfURL: url) {
// cell!.imageView?.image = UIImage(data: data)
// }
cell.titleLabel.text = posts.objectAtIndex(indexPath.row).valueForKey("title") as! NSString as String
// if NSUserDefaultsImage {
// cell.sideImageView.image = NSUserDefaultsImage[indexPath.row]
// }else{
downloadFileFromURL(NSURL(string: self.posts.objectAtIndex(indexPath.row).valueForKey("enclosure") as! String)!, completionHandler:{(img) in
dispatch_async(dispatch_get_main_queue(), { () -> Void in
cell.sideImageView.image = img
// self.NSUserDefaultsImage.append(img)
// print(img)
// self.newsDefaults.setObject(self.NSUserDefaultsImage, forKey: "imgData")
})
})
// }
//cell.date.text = posts.objectAtIndex(indexPath.row).valueForKey("pubDate") as? String
//cell.sideImageView?.contentMode = UIViewContentMode.ScaleAspectFit
//cell.sideImageView?.image = image
cell.titleLabel.userInteractionEnabled = false
cell.titleLabel.editable = false
cell.titleLabel.selectable = false
return cell
}
func downloadFileFromURL(url1: NSURL?,completionHandler: CompletionHandler) {
// download code.
if let url = url1{
let priority = DISPATCH_QUEUE_PRIORITY_HIGH
dispatch_async(dispatch_get_global_queue(priority, 0)) {
let data = NSData(contentsOfURL: url)
if data != nil {
print("image downloaded")
completionHandler(image: UIImage(data: data!)!)
}
}
}
}
}
In order to save images to NSUserDefaults you will need to turn it into NSData as there are only certain types that are allowed in there.
As for the idea of storing information in there for offline viewing.... That sounds more like a job for the Applications Document directory. You should be able to use the NSCoding protocol in your objects and write all of your information to the disk by calling
NSKeyedArchiver:archiveRootObject:toFile on the main object and it will call encodeWithCoder on all the child objects.
Saving large data in NSUserDefault in not recommended by Apple and we should not save large data. NSUserDefault or Keychain we use to store "Username", "Password" like less information.
You can use CoreData or Sqlite to do operatation with Data.
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'm trying to create a rss-feed app with a UITableView to show the RSS-content(title and description). The NSXMLparser works fine, it can get all the information from the website. However I seem to have a problem with getting the information into the UITableView and I can't seem to find where I did wrong!
I've set the UItableView's cell's reuseIdentifier to Cell.
The titlesTableView is connected as shown in the code as an IBOutlet.
I'm sorry for the long code, but I don't know where it went wrong.
import UIKit
class SecondViewController: UIViewController, NSXMLParserDelegate {
var xmlParser: NSXMLParser!
var entryTitle: String!
var entryDescription: String!
var entryLink: String!
var currentParsedElement:String! = String()
var entryDictionary: [String:String]! = Dictionary()
var entriesArray:[Dictionary<String, String>]! = Array()
#IBOutlet var titlesTableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
self.titlesTableView.estimatedRowHeight = 40.0
let urlString = NSURL(string: "http://www.skeppsfast.se/aktuellt.feed?type=rss")
let rssUrlRequest:NSURLRequest = NSURLRequest(URL:urlString!)
let queue:NSOperationQueue = NSOperationQueue()
NSURLConnection.sendAsynchronousRequest(rssUrlRequest, queue: queue) {
(response, data, error) -> Void in
self.xmlParser = NSXMLParser(data: data!)
self.xmlParser.delegate = self
self.xmlParser.parse()
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
//MARK: NSXMLParserDelegate
func parser(parser: NSXMLParser!,
didStartElement elementName: String!,
namespaceURI: String!,
qualifiedName: String!,
attributes attributeDict: [String : String]!){
if elementName == "title"{
entryTitle = String()
currentParsedElement = "title"
}
if elementName == "description"{
entryDescription = String()
currentParsedElement = "description"
}
if elementName == "link"{
entryLink = String()
currentParsedElement = "link"
}
}
func parser(parser: NSXMLParser!,
foundCharacters string: String!){
if currentParsedElement == "title"{
entryTitle = entryTitle + string
}
if currentParsedElement == "description"{
entryDescription = entryDescription + string
}
if currentParsedElement == "link"{
entryLink = entryLink + string
}
}
func parser(parser: NSXMLParser!,
didEndElement elementName: String!,
namespaceURI: String!,
qualifiedName qName: String!){
if elementName == "title"{
entryDictionary["title"] = entryTitle
}
if elementName == "link"{
entryDictionary["link"] = entryLink
}
if elementName == "description"{
entryDictionary["description"] = entryDescription
entriesArray.append(entryDictionary)
}
}
func parserDidEndDocument(parser: NSXMLParser!){
dispatch_async(dispatch_get_main_queue(), { () -> Void in
self.titlesTableView.reloadData()
})
}
// MARK: UITableViewDataSource
func tableView(tableView: UITableView,
cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell{
var cell:UITableViewCell! = tableView.dequeueReusableCellWithIdentifier("Cell")as UITableViewCell!
if (nil == cell){
cell = UITableViewCell(style: UITableViewCellStyle.Subtitle, reuseIdentifier: "Cell")
}
cell!.textLabel?.text = entriesArray[indexPath.row]["title"]
cell!.textLabel?.numberOfLines = 0
cell!.detailTextLabel?.text = entriesArray[indexPath.row]["description"]
cell!.accessoryType = UITableViewCellAccessoryType.DisclosureIndicator
return cell
}
func tableView(tableView: UITableView,
numberOfRowsInSection section: Int) -> Int{
return entriesArray.count
}
}
Turns out I hadn't add the UITableViewDataSource protocol to the class (stupid me).
Should have been:
class SecondViewController: UIViewController, NSXMLParserDelegate, UITableViewDataSource {
My confidence just dropped a ton after this taking me about a day and a half to solve.
I worked on my XML feed reader with a TableViewControllerand it was working perfectly but as it's not flexible, I wanted to move to another ViewController which includes `TableView'. However, even though I think I made the connections right (creating IBOutlet from tableview, using the right objects in custom cell in CustomCell class etc), it shows blank cells.
You can find the code below. I am using CustomCell class to create my custom cell. What am I missing here?
class originalViewController: UIViewController,UITableViewDelegate, NSXMLParserDelegate, UIScrollViewDelegate{
#IBOutlet var tableView: UITableView!
var parser = NSXMLParser()
var feeds = NSMutableArray()
var elements = NSMutableDictionary()
var element = NSString()
var ftitle = NSMutableString?()
var link = NSMutableString?()
var fdescription = NSMutableString?()
var fIMG = NSMutableString?()
var fAuthor = NSMutableString?()
var fDate = NSMutableString?()
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: "Cell")
feeds = []
var url = NSURL(string: "http://www.marketoloji.com/?feed=rss2")
parser = NSXMLParser(contentsOfURL: url)!
parser.delegate = self
parser.shouldProcessNamespaces = false
parser.shouldReportNamespacePrefixes = false
parser.shouldResolveExternalEntities = false
parser.parse()
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "openPage" {
var indexPath: NSIndexPath = self.tableView.indexPathForSelectedRow()!
let wvc: WebViewController = segue.destinationViewController as WebViewController
var selectedURL: String = feeds[indexPath.row].objectForKey("link") as String
selectedURL = selectedURL.stringByReplacingOccurrencesOfString(" ", withString: "")
selectedURL = selectedURL.stringByReplacingOccurrencesOfString("\n", withString: "")
wvc.selectedLink = selectedURL
}
}
func parser(parser: NSXMLParser!, didStartElement elementName: String!, namespaceURI: String!, qualifiedName qName: String!, attributes attributeDict: [NSObject : AnyObject]!) {
element = elementName
if (element as NSString).isEqualToString("item"){
elements = NSMutableDictionary.alloc()
elements = [:]
ftitle = ""
link = ""
fdescription = ""
fAuthor = ""
fDate = ""
fIMG = ""
} else if element.isEqualToString("enclosure") {
var imgLink = attributeDict["url"] as String
imgLink = imgLink.stringByReplacingOccurrencesOfString(" ", withString: "")
imgLink = imgLink.stringByReplacingOccurrencesOfString("\n", withString: "")
fIMG?.appendString(imgLink)
println(imgLink)
}
}
func parser(parser: NSXMLParser!, didEndElement elementName: String!, namespaceURI: String!, qualifiedName qName: String!){
if (elementName as NSString).isEqualToString("item"){
if ftitle != nil {
elements.setObject(ftitle!, forKey: "title")
}
if link != nil {
elements.setObject(link!, forKey: "link")
}
if fdescription != nil {
elements.setObject(fdescription!, forKey: "description")
}
if fAuthor != nil {
elements.setObject(fAuthor!, forKey: "creator")
}
if fDate != nil {
elements.setObject(fDate!, forKey: "date")
}
if fIMG != nil {
elements.setObject(fIMG!, forKey: "imageLink")
}
feeds.addObject(elements)
}
}
func parser(parser: NSXMLParser!, foundCharacters string: String!) {
if element.isEqualToString("title") {
ftitle?.appendString(string)
} else if element.isEqualToString("link") {
link?.appendString(string)
} else if element.isEqualToString("description") {
fdescription?.appendString(string)
} else if element.isEqualToString("dc:creator") {
fAuthor?.appendString(string)
} else if element.isEqualToString("pubDate") {
fDate?.appendString(string)
}
}
func parserDidEndDocument(parser: NSXMLParser!) {
self.tableView.reloadData()
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 20
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
//let cell: CustomCell = tableView.dequeueReusableCellWithIdentifier("Cell") as CustomCell
let cell:CustomCell = self.tableView.dequeueReusableCellWithIdentifier("Cell") as CustomCell
cell.setCell(feeds.objectAtIndex(indexPath.row).objectForKey("title") as String, fDescription: feeds.objectAtIndex(indexPath.row).objectForKey("description") as String, fAuthor: feeds.objectAtIndex(indexPath.row).objectForKey("creator") as String, fDate: feeds.objectAtIndex(indexPath.row).objectForKey("date") as String, fImage: feeds.objectAtIndex(indexPath.row).objectForKey("imageLink") as String)
//cell.backgroundColor = UIColor.clearColor()
return cell
}
}
Figured out that I didnt connect the delegate and datasource of the table to the view controller, that was the main problem.
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.