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.
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()
...
}
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 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.
I'm getting 'Client' is not convertible to 'AFOAuthSignatureMethod' for this line: if self.selectedClient == client { in the body of the cellForRowAtIndexPath method.
No idea why is it comparing AFOAuthSignatureMethod. An Xcode bug?
Client.swift
import Foundation
class Client {
var id : String!
var organization : String!
init(id: String, organization: String) {
self.id = id
self.organization = organization
}
}
SelectController.swift
import UIKit
class SelectController: UITableViewController, NSXMLParserDelegate {
// MARK: Properties
var clients : [Client] = []
var selectedClient : Client!
var elemName : String!
var clientId : String!
var organization : String!
required init(coder aDecoder: NSCoder!) {
super.init(coder: aDecoder)
}
override func viewDidLoad() {
super.viewDidLoad()
var defaults = NSUserDefaults.standardUserDefaults()
let accountData = defaults.objectForKey("credentials") as NSDictionary!
if accountData == nil {
let authController = self.storyboard.instantiateViewControllerWithIdentifier("AuthController") as AuthController
self.navigationController.pushViewController(authController, animated: false)
}
if clients.count > 0 {
self.tableView.reloadData()
} else {
let accountName = accountData["accountName"] as String
let key = accountData["key"] as String
let secret = accountData["secret"] as String
let baseURL = "https://\(accountName).freshbooks.com"
var token = AFOAuth1Token(key: key, secret: secret, session: nil, expiration: nil, renewable: true)
var freshbooksClient = AFOAuth1Client(
baseURL: NSURL.URLWithString(baseURL),
key: consumerKey,
secret: consumerSecret
)
freshbooksClient.accessToken = token
freshbooksClient.signatureMethod = AFOAuthSignatureMethod.AFPlainTextSignatureMethod
let requestBody = "<?xml version=\"1.0\" encoding=\"utf-8\"?><request method=\"client.list\"></request>"
var request = freshbooksClient.requestWithMethod("POST", path: "/api/2.1/xml-in", parameters: nil)
request.HTTPBody = requestBody.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)
request.HTTPMethod = "POST"
var operation = AFXMLRequestOperation(request: request)
freshbooksClient.registerHTTPOperationClass(AFXMLRequestOperation)
operation.setCompletionBlockWithSuccess(
{ (operation : AFHTTPRequestOperation!, responseObject) in
var parser = responseObject as NSXMLParser
parser.delegate = self
parser.parse()
},
failure: { (operation, error) in
println("Error: " + error.description)
}
)
operation.start()
}
}
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 clients.count
}
override func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell! {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as UITableViewCell
var client = clients[indexPath.row]
cell.textLabel.text = client.organization
if self.selectedClient == client {
cell.accessoryType = UITableViewCellAccessoryType.Checkmark
} else {
cell.accessoryType = UITableViewCellAccessoryType.None
}
return cell
}
override func tableView(tableView: UITableView!, didDeselectRowAtIndexPath indexPath: NSIndexPath!) {
self.selectedClient = clients[indexPath.row]
tableView.reloadRowsAtIndexPaths([indexPath], withRowAnimation: UITableViewRowAnimation.None)
}
// MARK: Navigation
override func prepareForSegue(segue: UIStoryboardSegue!, sender: AnyObject!) {
}
// MARK: Parser
func parser(parser: NSXMLParser!, didStartElement elementName: String!, namespaceURI: String!, qualifiedName qName: String!, attributes attributeDict: NSDictionary!) {
elemName = elementName
}
func parser(parser: NSXMLParser!, didEndElement elementName: String!, namespaceURI: String!, qualifiedName qName: String!) {
if elementName == "client" {
var client = Client(id: clientId, organization: organization)
clients.append(client)
}
}
func parser(parser: NSXMLParser!, foundCharacters string: String!) {
let data = string.stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceAndNewlineCharacterSet())
if (!data.isEmpty) {
if elemName == "client_id" {
clientId = data
} else if elemName == "organization" {
organization = data
}
}
}
func parserDidEndDocument(parser: NSXMLParser!) {
// Sort clients alphabetically
clients.sort({ $0.organization < $1.organization })
self.tableView.reloadData()
}
}
The error message is misleading. The problem is that the equal operator == is not
defined for your Client class in
if self.selectedClient == client { ... }
Possible solutions:
Use the identity operator === instead:
if self.selectedClient == client { ... }
This checks whether the object references both refer to the same object instance.
Make your class inherit from NSObject:
class Client : NSObject { ... }
Then the class inherits the isEqual: method from NSObject (which also compares
the object pointers unless overridden).
Implement == for your class, for example:
func ==(lhs: Client, rhs: Client) -> Bool {
return lhs.id == rhs.id && lhs.organization == rhs.organization
}
In your case the first solution is probably the right one.