iOS Programming · · 7 min read

How to Create a Simple RSS Reader App

How to Create a Simple RSS Reader App

Editor’s note: we received a number of requests for a tutorial about building a RSS reader app. This week, Rafael Garcia Leiva will show you how to create a simple iPhone app to consume a RSS feed. Rafael is a senior iPhone developer author of more than a dozen applications. Currently he works as freelancer developing iPhone applications and teaching introductory and advanced courses about iPhone programming. When away from a keyboard Rafael spends his time on the mountains with his wife and three children.

Enter the RSS Reader tutorial.

In this tutorial, we are going to learn how to create a simple RSS reader application. The app will be based on a master / detail design, where the master view will display the list of available feeds, and the detail view will show the corresponding web pages.

Simple RSS Reader Tutorial

Simple RSS Reader Tutorial

The core of the application is the NSXMLParser class. NSXMLParser is the XML parser included by default with the iPhone SDK. NSXMLParser is a SAX parser, which means that it adopts an event-driven style of parsing XML files: whenever the parser has finished the processing of a part of the XML file, it calls a method from the parser’s delegate.

Creating a Master Detail Application

Open Xcode and create a new Project, choose the template Master Detail Application as shown below.

Creating a new Xcode Project

Creating a new Xcode Project

In the next screen, enter RSSreader as the product name and set com.appcoda in the company identifier field. Don’t forget to select the “User Storyboard” and “Use Automatic Reference Counting” options. Press next and create.

Xcode Project Identification

Setting the project option

Designing the User Interface

Select the MainStoryboard.storyboard file from Xcode’s Navigator to display the storyboard on the Editor pane.

RSS Reader Storyboard

RSS Reader Storyboard

As you can see, we already have all the elements we need for our reader:

  • A Navigation Bar to go back and forward from the stories.
  • A Table View to display the list of available stories.
  • A Detailed View that will contain a Web View to display the selected story.

However, we still need to make a few changes in the storyboard to have a fully functional user interface.

First select the Master View Controller and change the Navigation Bar title from “Master” to “Stories”, or to any other title you prefer. Then, click on the Assistant Editor button to open the source code associated to our Master View Controller (APPMasterViewController.h), and create an IBOutlet for our Table View (control drag from the UITableView to the source code).

Creating an outlet for table view

Creating an outlet for table view

In the Connection field we have to choose Outlet, as Name use tableView, as Type select UITableView, and finally, as Storage select Strong. That should create the following IBOutlet:

 @property (strong, nonatomic) IBOutlet UITableView *tableView; 

Now select the Detail View Controller and change again the title of the Navigation Bar; instead of “Detail” write “Content”. Then we have to remove the label in the center of the View, since we are not going to use it. Do not forget to remove the IBOutlet property form the APPDetailViewController.h file, and remove the detailItem property as well. Finally, drag and drop an UIWebView from the Object Library to the Detail View Controller View. Make sure that the web view takes all the available space.

Adding a web view

Adding a web view

Again, we have to create an IBOutlet form the UIWebView. Using the same procedure described above, control drag an outlet to the APPDetailViewController.h file, and call it webView. Add also another @property of type NSString, and with copy modifier. The string property will contain the URL address of the current selected story. If you did everything correctly, the APPDetailViewController.h should be something like:

#import 

@interface APPDetailViewController : UIViewController

@property (copy, nonatomic) NSString *url;
@property (strong, nonatomic) IBOutlet UIWebView *webView;

@end

Implementing the Master View Controller

In the APPMasterViewController.m file, replace the @interface declaration by the following:

@interface APPMasterViewController () {

    NSXMLParser *parser;
    NSMutableArray *feeds;
    NSMutableDictionary *item;
    NSMutableString *title;
    NSMutableString *link;
    NSString *element;

}
@end

In this section we have declared several helper variables: parser is the object that will download and parse the RSS XML files; feeds is a mutable array that will contain the list of feeds downloaded; item is a mutable dictionary that will contains the details of a feed, in our case its title and its link; and finally, element will help us to control with element is currently parsing the NSXMLParser object.

In the viewDidLoad function we have to initialize and start the NSXMLParser object. For simplicity, in this example the URL for the feed is hard coded. We simple use the hot news feed from Apple (http://images.apple.com/main/rss/hotnews/hotnews.rss). In a production application, you should allow the user to change this address from the user interface.

- (void)viewDidLoad {

    [super viewDidLoad];

    feeds = [[NSMutableArray alloc] init];
    NSURL *url = [NSURL URLWithString:@"http://images.apple.com/main/rss/hotnews/hotnews.rss"];
    parser = [[NSXMLParser alloc] initWithContentsOfURL:url];

    [parser setDelegate:self];
    [parser setShouldResolveExternalEntities:NO];
    [parser parse];

}

Next remove the insertNewObject method, since we will not allow the user to add feeds manually, and replace the methods for managing the table by the following:

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return 1;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return feeds.count;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell" forIndexPath:indexPath];
    cell.textLabel.text = [[feeds objectAtIndex:indexPath.row] objectForKey: @"title"];
    return cell;
}

The only element that is new is the following line of code, where we set the title of the current cell to the title of the feed:

cell.textLabel.text = [[feeds objectAtIndex:indexPath.row] objectForKey: @"title"];

Remove also the canEditRowAtIndexPath and commitEditingStyle methods, since we do not need them for this application.

Implementing the Parser Delegate

Next we have to implement the parser delegate methods. In order to do that, we have to tell the compiler that the ENTMasterViewController class implements the NSXMLParserDelegate protocol. Open the ENTMasterViewController.h file and replace the class definition by:

@interface ENTMasterViewController : UITableViewController

Whenever the parser finds a new element, it calls the didStartElement method from its delegate. In that method we have to check that the element found is an “item”, and if so, we allocate the variables to store the item.

- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict {
    
	element = elementName;
    
	if ([element isEqualToString:@"item"]) {
        
		item    = [[NSMutableDictionary alloc] init];
		title   = [[NSMutableString alloc] init];
		link    = [[NSMutableString alloc] init];
        
    }
    
}

Then, the parser calls its delegate every time new characters are found. This is why we have to use mutable strings, since we have to add the new characters found to the previous ones. In our case we are interested in the “title” and “link” elements, but we could also store information about the “date” or “summary” of the story.

- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
    
	if ([element isEqualToString:@"title"]) {
		[title appendString:string];
	} else if ([element isEqualToString:@"link"]) {
		[link appendString:string];
	}
	
}

When the parser encounters the end of an element, it calls the didEndElement method. In that case we simply add the new object to the array of objects.

- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
    
	if ([elementName isEqualToString:@"item"]) {
        
		[item setObject:title forKey:@"title"];
		[item setObject:link forKey:@"link"];
		
		[feeds addObject:[item copy]];

	}
	
}

And when the parser encounters the end of the document, it calls the method parserDidEndDocument. In that case what we have to do is to inform to the UITableView to redisplay itself, since we have all the data to be displayed.

- (void)parserDidEndDocument:(NSXMLParser *)parser {
	
	[self.tableView reloadData];
    
}

Implementing the Detail View Controller

We need a way to inform to our Detail View Controller about the URL of the feed we want to display. In order to do that we use the prepareForSegue method of the Master View Controller, where we set the url property of the destintionViewController:

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    if ([[segue identifier] isEqualToString:@"showDetail"]) {
        
        NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
        NSString *string = [feeds[indexPath.row] objectForKey: @"link"];
        [[segue destinationViewController] setUrl:string];
     	 
    }
}

The last step is to modify the APPDetailViewController.m file. In our case, the Detail View Controller is very simple, we only need to provide the following viewDidLoad method, and safely remove the rest of the methods:

- (void)viewDidLoad {
    [super viewDidLoad];    
    NSURL *myURL = [NSURL URLWithString: [self.url stringByAddingPercentEscapesUsingEncoding:
                                          NSUTF8StringEncoding]];
    NSURLRequest *request = [NSURLRequest requestWithURL:myURL];
    [self.webView loadRequest:request];
}

The method just ask to the webView to display the content of the selected feed. For that, first we create an NSURL with the string we have, but escaping those characters that can create problems in an URK with the option using stringByAddingPercentEscapesUsingEncoding. And then, we create an NSURLRequest to download the web page with the story.

If you make no mistakes, you should be able to compile and run the RSS reader app in the simulator.

Simple RSS Reader App

Simple RSS Reader App

Download the Full Source Code

I hope you enjoy the tutorial. You should now have a basic idea of consuming RSS feed using NSURLRequest and NSXMLParser. For your complete reference, you can download the full source code from here.

We'll explore some more interesting things in the upcoming tutorials. As always, leave us comment and share your thought about the tutorials.

Read next