BlogReader App in Swift

In this iOS development tutorial, we will see how to write a blog feed Reader app in Swift Programming Language. For this demo, let us take the blog feed (https://rshankar.com/feed) from Learning Swift and iOS Development blog. This is a WordPress blog and the number of posts in the feed is set to 10 (This is configurable using WordPress Settings). For parsing this feed we will be using NSXMLParser and the parsed data will be displayed in a TableView. Then when the users taps on any post, the post URL will be displayed in a UIWebView.

Download source code from GitHub

201407311416.jpg 201407311417.jpg

Click File menu, select New then Project from the sub menu.

201407311021.jpg

In the template screen, choose Single View Application and click Next.

201407311022.jpg

In the options screen, enter the Product name and select language as Swift. Then choose a folder and save this new Project.

201407311024.jpg

Add a new TableViewController

Navigate to Main.storyboard and delete the default ViewController. From the object library, drag and drop a TableViewController on to the Storyboard.

201407311034.jpg

Now embed this TableViewController in a NavigationController, by clicking Editor menu and selecting Navigation Controller under Embed In menu option.

201407311035.jpg

Select ViewController.swift file under Project Navigator and delete the file.

201407311037.jpg

Right click on the Project folder and select New File option.

201407311038.jpg

In the Choose a template screen, select Cocoa Touch under iOS and click Next button.

201407311039.jpg

In the Choose options for new file screen, enter the class name as “BRTableViewController”, select Subclass of UITableViewController and Language as Swift.

201407311040.jpg

Using NSXMLParser for parsing the blog feed

Navigate to BRTableViewController.swift class declaration, add NSXMLParserDelegate after UITableViewController.

class BRTableViewController: UITableViewController, NSXMLParserDelegate{

This is required as we need to use some of the functions defined in NSXMLParserDelegate for parsing the feed. Now declare a NSXMLParser variable called parser.

var parser: NSXMLParser = NSXMLParser()

Then update the viewDidLoad method with the following code.

  override func viewDidLoad() {

super.viewDidLoad()

let url:NSURL = NSURL(string: “https://rshankar.com/feed”)

parser = NSXMLParser(contentsOfURL: url)

parser.delegate = self

parser.parse()

}

In the above lines of code, we are defining url for holding the feed. Then reinitialising the parser object with url and also setting the parser delegate to self. The parse( ) method would start parsing the feed. Before we write further code let us understand the structure of the blog feed. If you open the feed address (https://rshankar.com/feed) in your browser, you should notice the following XML structure.
201407311107.jpg
Each item element in the above screenshot provides details about the blog post. And on expanding item element, you should notice the following structure.
201407311110.jpg For this demo, we will be using the title and link elements only. The title will be displayed in the TableView and link will be displayed in UIWebView. In order to hold these title and link, let us create a placeholder class with two properties.
Right click on the Project folder, select New File and choose Swift File under iOS. Click Next and save the file as BlogPost.swift to the Project folder.
201407311132.jpg  
Navigate to BlogPost.swift, declare the class name as BlogPost and add two properties for holding title and link.

class BlogPost {

  

  var postTitle: String = String()

var postLink: String = String()

}

201407311200.jpg  
And to hold all the blog posts let us define variable of type array. Navigate to BRTableViewController.swift and add the following code after the parser variable

  var blogPosts: [BlogPost] = []

Implement the delegate method of NSXMLParser

Add the following three methods to BRTableViewController.swift. You can use Xcode autocomplete feature for adding these methods.

  // MARK: – NSXMLParserDelegate methods

  

func parser(parser: NSXMLParser!, didStartElement elementName: String!, namespaceURI: String!, qualifiedName qName: String!, attributes attributeDict: [NSObject : AnyObject]!) {

  

}

  

func parser(parser: NSXMLParser!, foundCharacters string: String!) {

  

}

  

func parser(parser: NSXMLParser!, didEndElement elementName: String!, namespaceURI: String!, qualifiedName qName: String!) {

  

}

  

As already observed in structure of the blog feed, the blog post is specified under the element named item. So we need to do all initialisation of the variables when the parser starts with this element name. Let us add the following the variables to the class declaration.

  var postTitle: String = String()

var postLink: String = String()

var eName: String = String()

Then initialise these variables didStartElement function when elementName is “item”

  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()

}

}

Then update foundCharacters function with the following code.

  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

}

}

}

In the above lines of code, we are removing the white space and newline character set. Then assign the values to corresponding variables if the content is not empty. Make sure to the append the values as the foundCharacters function will be called number of times for the same element name.
Then finally we add the following lines of code to didEndElement function. An instance of BlogPost is created and set with title and link values. Then this object is added to the blogPosts array.

  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

blogPosts.append(blogPost)

}

}

Displaying the content in TableViewController

Navigate to the Table View Data source section and remove the commented line in numberOfSectionsInTableView and set the return value as 1.

  override func numberOfSectionsInTableView(tableView: UITableView!) -> Int {

return 1

}

The number of rows iN the table view will be equivalent to the total count of objects in blogPosts array. Update numberOfRowsInSection to reflect the array count.

  override func tableView(tableView: UITableView!, numberOfRowsInSection section: Int) -> Int {

return blogPosts.count

}

Now uncomment cellForRowIndexPath function and update the function with the following lines of code.

  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

return cell

}

In the above lines of code, we have changed the cell identifier to “cell”. Then retrieved the content for the cell using the row index path from the blogPosts array. Then assigned the value of post title to cell’s textLabel.

Now navigate to Main.storyboard, select tableview cell and set the Identifier to Cell using the Attributes inspector.

201407311223.jpg

Then navigate to TableViewController and set the Class as BRTableViewController using the Identity inspector.

201407311224.jpg

Now if you compile and run the project in iOS simulator, you should see the list of blog posts as shown in the below screenshot.

201407311252.jpg

Let us make some cosmetic changes to the look of the table view. Navigate to Main.storyboard and add the title to navigation bar as Blog Reader.

201407311254.jpg

Then add the following function to BRTableViewController.swift for adjusting the row height of the tableview cell.

  override func tableView(tableView: UITableView!, heightForRowAtIndexPath indexPath: NSIndexPath!) -> CGFloat {

return 50.0

}

Now if you try to run the app on the simulator it should look as shown below.

201407311256.jpg

Displaying the post content in UIWebView

Now when users taps on post title, the user must be taken to another screen displaying the content of the post. For this purpose we to add another ViewController and use UIWebView for displaying the post content. Click Main.storyboard and add ViewController from object library to Storyboard. Now hold control and connect the UITableViewCell from BRTableViewController to the new ViewController, set the segue as “Show”. Then Provide the name of the Storyboard segue as viewpost.

201407311302.jpg

Add a UIWebView control from object library to ViewController. Right click on the Project folder and select New File for adding ViewController class.

201407311307.jpg

Select template as Cocoa Touch class and click Next button. Provide a name to the Class as PostViewController with Subclass of UIViewController. Then click Next and save the file to the Project folder.

201407311308.jpg

Using the Identity inspector the set the class name for the ViewController in the storyboard as PostViewController.

201407311311.jpg

Let us also add a UIActivityIndicatorView that would be displayed till the blog post is getting loaded on the WebView.

201407311313.jpg

Open PostViewController.swift file and add IBOutlets for UIWebView and UIActivityIndicatorView controls.

  @IBOutlet var webView:UIWebView!

@IBOutlet var activityIndicator: UIActivityIndicatorView!

In the class declaration, next to UIViewController add UIWebViewDelegate. This is required as we will be implementing two of the UIWebViewDelegate functions.

class PostViewController: UIViewController, UIWebViewDelegate

Then add the following postLink property, the value for this property will be set when the user taps any post on table view.

  var postLink: String = String()

Now update viewDidLoad function with following lines of code

  override func viewDidLoad() {

super.viewDidLoad()

let url: NSURL = NSURL(string: postLink)

let request: NSURLRequest = NSURLRequest(URL: url)

webView.loadRequest(request)

webView.delegate = self

}

The above lines of code, calls loadRequest of UIWebView by passing a NSURLRequest object. Then sets the delegate for webView to self. Now implement the following UIWebView delegate functions for showing and hiding Activity Indicator View.

  func webViewDidStartLoad(webView: UIWebView!) {

activityIndicator.hidden = false

activityIndicator.startAnimating()

}

  

func webViewDidFinishLoad(webView: UIWebView!) {

activityIndicator.hidden = true

activityIndicator.stopAnimating()

}

Finally use the connection inspector in the Interface builder to connect the IBOutlet variables (webView and activityIndicator) to the respective controls on the ViewController.

201407311318.jpg

Navigate to BRTableViewController.swift and add the prepareForSegue function. Check if the identifier is “viewpost” and then retrieve the post details for the selected row using tableView.indexPathForSelectedRow(). Then assign the post web url to viewController’s postLink property.

  override func prepareForSegue(segue: UIStoryboardSegue!, sender: AnyObject!) {

if segue.identifier == “viewpost” {

let blogPost: BlogPost = blogPosts[tableView.indexPathForSelectedRow().row]

let viewController = segue.destinationViewController as PostViewController

viewController.postLink = blogPost.postLink

}

}

Now if you compile and run the project, you should be able to view the post details on tapping any of the post in the table view.

201407311416.jpg

Download source code from GitHub


Comments

28 responses to “BlogReader App in Swift”

  1. Solid as a rock. Excellent step-by-step. Thanks.

  2. Otiimo very explanatory tutorial, you could possibly insert images in cells that reflect those of the blog and the date when it was added to the post?
    Thanks for the help that you provide to us beginners of programming ….

  3. Hello shankar!

    This looks a very good tutorial. By the way I’m using xcode-6 GM version but your source-code is not running. Even I tried to do code in Swift following your screenshots. But successfully failed 🙁 I’m new to ios development. So can you please help me to learn TableView with XMLParsing. Thanks in advance.

    1. Thanks for letting me know about the problem. The code has been updated now for Xcode 6 GM seed, please try now.

  4. Hello and thanks for the tutorial.
    The code works right except when running in a real device. I get a bad access code 1 in this line:

    parser = NSXMLParser(contentsOfURL: url)

    I try to fix it but im quite new and can´t.

    Thanks.

  5. Hello. Thanks for the tutorial.

  6. hey, thanks fot the code, but how can I parse image (by url) and show in the table view? i’ve create a custom cell that include the uiimageview.

    Thanks

  7. I’m struggling with getting this line in the very last step to work. It keeps throwing me an error:

    let blogPost: BlogPost = blogPosts[tableView.indexPathForSelectedRow().row]

    It says: ‘(UITableView, numberOfRowsInSection: Int) -> Int’ does not have a member named ‘indexPathForSelectedRow’

  8. Anthony Dias Avatar
    Anthony Dias

    Hey rshankar,

    Thanks for the code, its run, but doesn’t show nothing in simulator, only a tableview, and clicking in any cell, let us to webview with nothing too, why’s that?, please help!!!

    Thansk again….

    1. I just tried to the source again with Xcode 6.3 and didn’t see any problem?
      What is the version of Xcode and iOS SDK installed on your Mac?

  9. My Xcode is upgraded, I downloaded your code and run it here, and work fine, and i compered with my code, is equal, but my code not shows nothing in simulator, it runs but don’t show nothing… I don’t understand…

  10. Hey rshankar,
    I found the error, and now it runs nice, thanks for the code…
    thanks…

  11. Justin C. Avatar
    Justin C.

    Hey rshankar – great tutorial… as someone just starting out in Xcode, I really learned a lot! One question: is there a way to scale pages in the UIWebView (or in the PostViewController.swift file) so that each link, when tapped on in the TableView, loads the with the entire webpage showing? Right now, when I click on a link in the TableView, the webpage that loads only displays about 2/3 of the total page, and I have to pinch/zoom to see it all. Thanks!

    1. rshankar Avatar
      rshankar

      Have you tried UIWebView property scalesPageToFit = YES. Let me know if does not solve the problem.

      Thanks
      Ravi

      1. Justin C. Avatar
        Justin C.

        That worked, thank you!! I also tried setting the Constrain tool at the bottom of the Main.Storyboard to 0 instead of -16 (was -16 the default?), so I’m not sure if that had any effect, also. Thanks again for the scalesPagesToFit solution!

  12. In my RSS feed there is an image tag that begins “<IMG". I want to pull in the address and show the image in each cell like other RSS feeder apps do. Do I create a var of type string called entryPic. Kindly email me timbojill@gmail.com if I am going in the right direction.

    1. That sound ok to me. And when displaying the image, convert the string URL to UIImage.

      1. rshankar can i send you an email on what I have done thus far. What is it I cant seem to find it on your website. I have been developing for a few months. Actually I started years ago under Objective C. Then I stopped developing and then picked up a few months ago. Now there is swift which is kicking my butt. Can you give me an example on how to convert the string to a UIImage ?

        1. rshankar Avatar
          rshankar

          Sorry for the late response. Please mail me the details ravi@rshankar.com

  13. Any way to add more than one feed?

  14. I am running this in Xcode 7, and no blog posts are coming up in the table view.

    I am running the source code with no errors, any advice on a fix?

      1. This worked, thanks a lot.

  15. How could you make this fetch the rss data asynchronously?

  16. I am newbie, can you give project for me? Thanks very much!

  17. Hay Ravi,it’s very good tutorial. I have one question how to import image next to the title in table view?

    Thanks

  18. Hello Ravi, have a two question for you. How to display older post and how to create a favorite posts by tapping on some button?

    Thanks very much

    Milos

  19. Hi rshankar happy new year,

    What you have done is great approach and straight to the goal..
    I believe you can make it even better by adding some HTML to exclude some unwanted elements shown in the uiwebview such as native website menu for mobile view since it is running on an ios app…

    Thanks

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.