How to Make a Simple RSS Reader iPhone App Tutorial

18
2/3/2016 How to Make a Simple RSS Reader iPhone App Tutorial http://www.raywenderlich.com/2636/rssreadertutorialforioshowtomakeasimplerssreaderiphoneapp 1/18 We'll make a multithreaded RSS reader in this tutorial! Rss Reader Tutorial for iOS: How To Make A Simple RSS Reader iPhone App When making iOS apps that have to download data off of the Internet, you run into a lot of challenges. You have to: Write code to retrieve the data off of the network Write code to parse and interpret the data Write code to run the above in the background, so your app remains responsive Update your UI in an animated fashion as data arrives so the user can see what’s going on That’s a lot of different concepts to put together. So in this iPhone app tutorial, you’ll get handson experience doing exactly that by making a simple RSS reader app! This iPhone app tutorial was specially requested and sponsored by William Mottl, a kind supporter of this blog. Thank you William! Getting Started Start up XCode, go to File\New Project, choose iOS\Application\Navigationbased Application, and click Choose. Name the project RSSFun, and click Save. The first thing you’ll do is create a class to keep track of individual articles inside a RSS feed. Select the Classes group, go to File\New File, choose iOS\Cocoa Touch Class\ObjectiveC class, and click Next. Name the class RSSEntry.m, make sure “Also create RSSEntry.h” is checked, and click Finish. Replace RSSEntry.h with the following: #import <Foundation/Foundation.h> @interface RSSEntry : NSObject { NSString *_blogTitle; NSString *_articleTitle; NSString *_articleUrl; NSDate *_articleDate; } @property (copy) NSString *blogTitle; @property (copy) NSString *articleTitle; @property (copy) NSString *articleUrl; @property (copy) NSDate *articleDate; Ray Wenderlich on January 27, 2011

description

IOS Tutorial

Transcript of How to Make a Simple RSS Reader iPhone App Tutorial

Page 1: How to Make a Simple RSS Reader iPhone App Tutorial

2/3/2016 How to Make a Simple RSS Reader iPhone App Tutorial

http://www.raywenderlich.com/2636/rss­reader­tutorial­for­ios­how­to­make­a­simple­rss­reader­iphone­app 1/18

   

We'll make a multithreaded RSS reader inthis tutorial!

Rss Reader Tutorial for iOS: How ToMake A Simple RSS Reader iPhone App

When making iOS apps that have to download data off of theInternet, you run into a lot of challenges. You have to:

Write code to retrieve the data off of the network

Write code to parse and interpret the data

Write code to run the above in the background, so your appremains responsive

Update your UI in an animated fashion as data arrives so theuser can see what’s going on

That’s a lot of different concepts to put together. So in this iPhoneapp tutorial, you’ll get hands­on experience doing exactly that bymaking a simple RSS reader app!

This iPhone app tutorial was specially requested and sponsoredby William Mottl, a kind supporter of this blog. Thank you William!

Getting StartedStart up XCode, go to File\New Project, choose iOS\Application\Navigation­based Application, and click Choose. Namethe project RSSFun, and click Save.

The first thing you’ll do is create a class to keep track of individual articles inside a RSS feed. Select the Classes group,go to File\New File, choose iOS\Cocoa Touch Class\Objective­C class, and click Next. Name the class RSSEntry.m,make sure “Also create RSSEntry.h” is checked, and click Finish.

Replace RSSEntry.h with the following:

#import <Foundation/Foundation.h> @interface RSSEntry : NSObject { NSString *_blogTitle; NSString *_articleTitle; NSString *_articleUrl; NSDate *_articleDate;} @property (copy) NSString *blogTitle;@property (copy) NSString *articleTitle;@property (copy) NSString *articleUrl;@property (copy) NSDate *articleDate; 

Ray Wenderlich on January 27, 2011

Page 2: How to Make a Simple RSS Reader iPhone App Tutorial

2/3/2016 How to Make a Simple RSS Reader iPhone App Tutorial

http://www.raywenderlich.com/2636/rss­reader­tutorial­for­ios­how­to­make­a­simple­rss­reader­iphone­app 2/18

- (id)initWithBlogTitle:(NSString*)blogTitle articleTitle:(NSString*)articleTitle articleUrl:(NSString*)articleUrl articleDate:(NSDate*)articleDate; @end

As you can see, this is a very simple class that just stores information about each article: its title, url, and date, as well asthe name of the blog it came from.

Next replace RSSEntry.m iwth the following to complete the implementation:

#import "RSSEntry.h" @implementation RSSEntry@synthesize blogTitle = _blogTitle;@synthesize articleTitle = _articleTitle;@synthesize articleUrl = _articleUrl;@synthesize articleDate = _articleDate; - (id)initWithBlogTitle:(NSString*)blogTitle articleTitle:(NSString*)articleTitle articleUrl:(NSString*)articleUrl articleDate:(NSDate*)articleDate { if ((self = [super init])) { _blogTitle = [blogTitle copy]; _articleTitle = [articleTitle copy]; _articleUrl = [articleUrl copy]; _articleDate = [articleDate copy]; } return self;} - (void)dealloc { [_blogTitle release]; _blogTitle = nil; [_articleTitle release]; _articleTitle = nil; [_articleUrl release]; _articleUrl = nil; [_articleDate release]; _articleDate = nil; [super dealloc];} @end

Nothing fancy here – this just synthesizes the properties and creates an initializer for convenience.

Next let’s set up the table view controller so that it keeps a list of RSS entries, and displays information about each one inthe table. We’ll put some dummy entries in for now, and later on we’ll add the code to retrieve them from actual RSSfeeds on the Internet.

So go to RootViewController.h and make the following changes:

// Inside @interfaceNSMutableArray *_allEntries; // After @interface@property (retain) NSMutableArray *allEntries;

This instance variable and property will be used to keep a list of all RSS entries. Next make the following changes toRootViewController.m:

// At top of file

Page 3: How to Make a Simple RSS Reader iPhone App Tutorial

2/3/2016 How to Make a Simple RSS Reader iPhone App Tutorial

http://www.raywenderlich.com/2636/rss­reader­tutorial­for­ios­how­to­make­a­simple­rss­reader­iphone­app 3/18

#import "RSSEntry.h" // After @implementation@synthesize allEntries = _allEntries; // Add new method- (void)addRows { RSSEntry *entry1 = [[[RSSEntry alloc] initWithBlogTitle:@"1" articleTitle:@"1" articleUrl:@"1" articleDate:[NSDate date]] autorelease]; RSSEntry *entry2 = [[[RSSEntry alloc] initWithBlogTitle:@"2" articleTitle:@"2" articleUrl:@"2" articleDate:[NSDate date]] autorelease]; RSSEntry *entry3 = [[[RSSEntry alloc] initWithBlogTitle:@"3" articleTitle:@"3" articleUrl:@"3" articleDate:[NSDate date]] autorelease];   [_allEntries insertObject:entry1 atIndex:0]; [_allEntries insertObject:entry2 atIndex:0]; [_allEntries insertObject:entry3 atIndex:0]; } // Uncomment viewDidLoad and make it look like the following- (void)viewDidLoad { [super viewDidLoad];  self.title = @"Feeds"; self.allEntries = [NSMutableArray array]; [self addRows]; } // Replace return 0 in tableView:numberOfRowsInSection with thisreturn [_allEntries count]; // Modify tableView:cellForRowAtIndexPath below like the following- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath {  static NSString *CellIdentifier = @"Cell";  UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; if (cell == nil) { cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease]; }  RSSEntry *entry = [_allEntries objectAtIndex:indexPath.row];  NSDateFormatter * dateFormatter = [[[NSDateFormatter alloc] init] autorelease]; [dateFormatter setTimeStyle:NSDateFormatterMediumStyle]; [dateFormatter setDateStyle:NSDateFormatterMediumStyle]; NSString *articleDateString = [dateFormatter stringFromDate:entry.articleDate];  cell.textLabel.text = entry.articleTitle; cell.detailTextLabel.text = [NSString stringWithFormat:@"%@ - %@", articleDateString, entry.blogTitle];  return cell;

Page 4: How to Make a Simple RSS Reader iPhone App Tutorial

2/3/2016 How to Make a Simple RSS Reader iPhone App Tutorial

http://www.raywenderlich.com/2636/rss­reader­tutorial­for­ios­how­to­make­a­simple­rss­reader­iphone­app 4/18

} // In dealloc[_allEntries release];_allEntries = nil;

Most of this is straightforward, but here are a few notes of explanation:

addRows is a helper method to create three dummy entries into the list just to make sure the display code isworking.

The table view is set up to display the entries by modifying tableView:numberOfRowsInSection to return thenumber of rows in the allEntries array, and tableView:cellForRowAtIndexPath is modified to use theUITableViewCellStyleSubtitle style, and sets up the title and subtitle fields according to the current entry.

Note that to display an NSDate as a string, you should use the NSDateFormatter class. You can specify defaultstyles like we do here (NSDateFormatterMediumStyle), or specify custom styles as well.

Compile and run your code, and you should now see three test entries in the list!

Downloading RSS Feeds Asynchronously with ASIHTTPRequestYou can download data from the Internet directly with the iOS SDK with NSURLRequest and NSURLConnection, but Iprefer to use a set of helper classes written by Ben Copsey called ASIHTTPRequest. It simplifies things and has a lot ofneat and helpful features.

The ASIHTTPRequest page has great instructions on how to integrate the code into your project, but I’ll post the steps

Page 5: How to Make a Simple RSS Reader iPhone App Tutorial

2/3/2016 How to Make a Simple RSS Reader iPhone App Tutorial

http://www.raywenderlich.com/2636/rss­reader­tutorial­for­ios­how­to­make­a­simple­rss­reader­iphone­app 5/18

here as well for quick reference:

1. Go to to your RSSFun project directory in Finder, and make a new folder called ASIHTTPRequest, as a sibling toyour Classes Folder.

2. Now download the ASIHTTPRequest source.

3. Untar the file to expand the source into a folder.

4. Copy all of the files from the Classes directory that begin with ASI (but not the folders) to yourRSSFun\ASIHTTPRequest folder.

5. Also copy all of the files from the External\Reachability directory to your RSSFun\ASIHTTPRequest folder.

6. Back in XCode, right control­click the RSSFun entry at the top of the Groups & Files tree, and choose Add\NewGroup. Name the new group ASIHTTPRequest.

7. Control­click your new ASIHTTPRequest group, and choose Get Info. In the General tab, click the Choose button,and browse to your RSSFun\ASIHTTPRequest folder to link the group to your file system. When you’re done, closethe dialog.

8. Control­click your new ASIHTTPRequest gorup again, and choose Add\Existing Files. Select all of the files inRSSFun\ASIHTTPRequest, and click Add, and Add again.

9. Finally, expand Targets and double click on the RSSFun target. In the General tab under Linked Libraries, click theplus button. Select CFNetwork.framework, and click Add. Then repeat for SystemConfiguration.framework,MobileCoreServices.framework, and libz.1.2.3.dylib. When you’re done, close the dialog.

Phew! Do a quick compile to make sure everything’s OK so far, then it’s time to add some code to try outASIHTTPRequest.

First, modify RootViewController.h to add two new instance variables/properties:

// Inside @interfaceNSOperationQueue *_queue;NSArray *_feeds; // After @interface@property (retain) NSOperationQueue *queue;@property (retain) NSArray *feeds;

The first instance variable is an NSOperationQueue. If you are not familiar with NSOperationQueue, it’s a class that letsyou queue operations – basically bits of code that need to be run at some point. NSOperationQueue will then run thetasks in the background, as system resources allow.

NSOperationQueue is basically a layer on top of threads. It’s a highly configurable class with some neat functionality, butfor this project we just need a default NSOperationQueue because we want to run some code in the background easily.

The feeds array is just an NSArray that will hold the URLs for the RSS feeds we wish to display. We’ll just hardcode insome feeds for the purposes of this app.

Next, switch to RootViewController.m and make the following changes:

// Add to top of file#import "ASIHTTPRequest.h" // Add under @implementation@synthesize feeds = _feeds;@synthesize queue = _queue; // Add new method- (void)refresh {

Page 6: How to Make a Simple RSS Reader iPhone App Tutorial

2/3/2016 How to Make a Simple RSS Reader iPhone App Tutorial

http://www.raywenderlich.com/2636/rss­reader­tutorial­for­ios­how­to­make­a­simple­rss­reader­iphone­app 6/18

for (NSString *feed in _feeds) { NSURL *url = [NSURL URLWithString:feed]; ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url]; [request setDelegate:self]; [_queue addOperation:request]; } } // Modify viewDidLoad as follows- (void)viewDidLoad { [super viewDidLoad]; self.title = @"Feeds"; self.allEntries = [NSMutableArray array]; self.queue = [[[NSOperationQueue alloc] init] autorelease]; self.feeds = [NSArray arrayWithObjects:@"http://feeds.feedburner.com/RayWenderlich", @"http://feeds.feedburner.com/vmwstudios", @"http://idtypealittlefaster.blogspot.com/feeds/posts/default", @"http://www.71squared.com/feed/", @"http://cocoawithlove.com/feeds/posts/default", @"http://feeds2.feedburner.com/brandontreb", @"http://feeds.feedburner.com/CoryWilesBlog", @"http://geekanddad.wordpress.com/feed/", @"http://iphonedevelopment.blogspot.com/feeds/posts/default", @"http://karnakgames.com/wp/feed/", @"http://kwigbo.com/rss", @"http://shawnsbits.com/feed/", @"http://pocketcyclone.com/feed/", @"http://www.alexcurylo.com/blog/feed/", @"http://feeds.feedburner.com/maniacdev", @"http://feeds.feedburner.com/macindie", nil]; [self refresh];} // In dealloc[_queue release];_queue = nil;[_feeds release];_feeds = nil;

Let’s stop here for a moment before we continue on. To use ASIHTTPRequest, you first need to import the header file, sowe do so here. We also synthesize the two new properties.

Next, there’s a method called refresh that starts the downloading of the RSS feeds in the background. This is very easyto do with ASIHTTPRequest. You simply need to create an ASIHTTPRequest object, and start it running. For this iPhoneapp tutorial, we’re going to start it running by adding it as an operation to our operation queue, so the system canefficiently manage the threading behavior for us.

So the refresh method loops through the list of feeds, and calls ASIHTTPRequest requestWithURL for each URL tocreate a request that will download the data, and queues it up to run at some point by adding it to the operation queue.

When the data finishes downloading, by default ASIHTTPRequest will call methods named requestFinished orrequestFailed on its delegate, so we set ourselves as the delegate (and we’ll write those methods next).

Also, we modify viewDidLoad here to initialize a default NSOperationQueue, and hard­code some RSS feeds to retrieve.

Ok, now let’s implement the requestFinished and requestFailed methods, that will be called after the data is downloadedfor each RSS feed:

- (void)requestFinished:(ASIHTTPRequest *)request { 

Page 7: How to Make a Simple RSS Reader iPhone App Tutorial

2/3/2016 How to Make a Simple RSS Reader iPhone App Tutorial

http://www.raywenderlich.com/2636/rss­reader­tutorial­for­ios­how­to­make­a­simple­rss­reader­iphone­app 7/18

RSSEntry *entry = [[[RSSEntry alloc] initWithBlogTitle:request.url.absoluteString articleTitle:request.url.absoluteString articleUrl:request.url.absoluteString articleDate:[NSDate date]] autorelease]; int insertIdx = 0; [_allEntries insertObject:entry atIndex:insertIdx]; [self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:insertIdx inSection:0]] withRowAnimation:UITableViewRowAnimationRight]; } - (void)requestFailed:(ASIHTTPRequest *)request { NSError *error = [request error]; NSLog(@"Error: %@", error);}

After the data finishes downloading, we can access the downloaded data with [request responseString] or [requestresponseData]. But right now, we aren’t really going to worry about the content of the data – instead we’ll just update thetable view with a dummy entry so we can visually see that the data has downloaded.

So when requestFinished is called, it creates a new RSSEntry that eventually needs to be added to the allEntries arrayand displayed in the table view. This callback method is called on the main thread, so it’s safe to update the allEntriesarray and table view directly.

Note that the table view is updated with insertRowsAtIndexPaths rather than just calling reloadData. This makes for anice animated display as new rows come in, rather than a disruptive reloadData.

Compile and run the code, and you should now see dummy entries for each feed fly in as the data is downloaded!

Page 8: How to Make a Simple RSS Reader iPhone App Tutorial

2/3/2016 How to Make a Simple RSS Reader iPhone App Tutorial

http://www.raywenderlich.com/2636/rss­reader­tutorial­for­ios­how­to­make­a­simple­rss­reader­iphone­app 8/18

Parsing the Feeds with GDataXMLRSS feeds are basically XML in one of two formats: RSS and Atom. One fast and easy API you can use to parse XML iniOS is GDataXML, so we’ll use that here.

To integrate GDataXML into your project, take the following steps:

1. Go to to your RSSFun project directory in Finder, and make a new folder called GDataXML, as a sibling to yourClasses Folder.

2. Download the gdata­objective­c client library.

3. Unzip the file, navigate to Source\XMLSupport, and copy the two files into your RSSFun\GDataXML folder.

4. Back in XCode, right control­click the RSSFun entry at the top of the Groups & Files tree, and choose Add\NewGroup. Name the new group GDataXML.

5. Control­click your new GDataXML group, and choose Get Info. In the General tab, click the Choose button, andbrowse to your RSSFun\GDataXML folder to link the group to your file system. When you’re done, close the dialog.

6. Control­click your new GDataXML gorup again, and choose Add\Existing Files. Select all of the files in RSSFun\GDataXML, and click Add, and Add again.

7. Click Project\Edit Project Settings, go to the Build tab, and make sure “All Configurations” are checked.

8. Find the Search Paths\Header Search Paths setting and add /usr/include/libxml2 to the list.

9. Finally, find the Linking\Other Linker Flags section and add ­lxml2 to the list.

Page 9: How to Make a Simple RSS Reader iPhone App Tutorial

2/3/2016 How to Make a Simple RSS Reader iPhone App Tutorial

http://www.raywenderlich.com/2636/rss­reader­tutorial­for­ios­how­to­make­a­simple­rss­reader­iphone­app 9/18

Compile the project to make sure everything builds OK – then it’s time to add some code.

In GDataXML, the class that you use to work with XML elements is, not surprisingly, called GDataXMLElement. We’ll beusing this a lot while parsing XML, so let’s add a little helper method to the class to save ourself some repetitive code. Socontrol­click on GDataXML, choose Add\New File, choose iOS\Cocoa Touch Class\Objective­C class, and click Next.Name the class GDataXMLElement­Extras.m, make sure “Also create GDataXMLElement­Extras.h” is checked, and clickFinish.

Replace GDataXMLElement­Extras.h with the following:

#import <Foundation/Foundation.h>#import "GDataXMLNode.h" @interface GDataXMLElement (Extras) - (GDataXMLElement *)elementForChild:(NSString *)childName;- (NSString *)valueForChild:(NSString *)childName; @end

This defines the two helper methods we’re adding – one to get a single GDataXMLElement for a child with a givenname, and one to get a string value for a specified child.

Next add the implementation by replacing GDataXMLElement­Extras.m:

#import "GDataXMLElement-Extras.h" @implementation GDataXMLElement(Extras) - (GDataXMLElement *)elementForChild:(NSString *)childName { NSArray *children = [self elementsForName:childName]; if (children.count > 0) { GDataXMLElement *childElement = (GDataXMLElement *) [children objectAtIndex:0]; return childElement; } else return nil;} - (NSString *)valueForChild:(NSString *)childName { return [[self elementForChild:childName] stringValue]; } @end

The first method uses the built­in elementsForName method to get all of the child elements of the current node given thespcified name. If there’s at least one, it returns the first child, otherwise it returns nil. Similarly, valueForChild callselementForChild, then stringValue on the result. This is very simple stuff – but again, we’re just adding it to saveourselves from having to type this over and over.

Next, make the following changes to RootViewController.m:

// Add to top of file#import "GDataXMLNode.h"#import "GDataXMLElement-Extras.h" // Modify requestFinished as follows- (void)requestFinished:(ASIHTTPRequest *)request {  [_queue addOperationWithBlock:^{  NSError *error; GDataXMLDocument *doc = [[GDataXMLDocument alloc] initWithData:[request

Page 10: How to Make a Simple RSS Reader iPhone App Tutorial

2/3/2016 How to Make a Simple RSS Reader iPhone App Tutorial

http://www.raywenderlich.com/2636/rss­reader­tutorial­for­ios­how­to­make­a­simple­rss­reader­iphone­app 10/18

responseData] options:0 error:&error]; if (doc == nil) { NSLog(@"Failed to parse %@", request.url); } else {  NSMutableArray *entries = [NSMutableArray array]; [self parseFeed:doc.rootElement entries:entries];   [[NSOperationQueue mainQueue] addOperationWithBlock:^{  for (RSSEntry *entry in entries) {  int insertIdx = 0; [_allEntries insertObject:entry atIndex:insertIdx]; [self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:insertIdx inSection:0]] withRowAnimation:UITableViewRowAnimationRight];  }   }];  } }]; }

Ok, so some major changes to requestFinished to add the code to parse the XML feed.

The first thing we do is queue up the code to parse the XML feed to be run in the background. This is because parsingthe XML feed might take a while, and we don’t want the UI to hang as it’s parsing the XML.

Again, we can make use of the operation queue to do this, by adding some code to be run on the queue. In iOS4, there’sa helper method that makes this extremely easy to do called addOperationWithBlock, so we make use of that here.

Inside the block of code to be run, we parse the document by calling GDataXML’s initWithData method, passing it thedata read from the network ([request responseData]). If it successfully parses into memory as a DOM model, we call ahelper method (which we’re about to write) called parseFeed, passing in the root element and an array it should add anyarticles into as RSSEntries.

After the RSSEntries are added to the array, we need to update the table view. But because we queued up the operationto run on the operation queue in the background, we can’t update the UI or our allEntries array, since a) you can’t updatethe UI on a background thread, and b) our allEntries array is not protected by a mutex, so should only be accessed onthe main thread.

So we get around this by simply adding another block of code to be run on [NSOperationQueue mainQueue], which isthe same as the main thread. This routine takes the entries to display, and adds them into the allEntries array and alsokeeps the tableView up to date.

Ok next up, adding the helper method to parse a RSS feed:

- (void)parseFeed:(GDataXMLElement *)rootElement entries:(NSMutableArray *)entries { if ([rootElement.name compare:@"rss"] == NSOrderedSame) { [self parseRss:rootElement entries:entries]; } else if ([rootElement.name compare:@"feed"] == NSOrderedSame) { [self parseAtom:rootElement entries:entries]; } else { NSLog(@"Unsupported root element: %@", rootElement.name); } }

Page 11: How to Make a Simple RSS Reader iPhone App Tutorial

2/3/2016 How to Make a Simple RSS Reader iPhone App Tutorial

http://www.raywenderlich.com/2636/rss­reader­tutorial­for­ios­how­to­make­a­simple­rss­reader­iphone­app 11/18

This looks at the root element to see if it’s rss (RSS format) or feed (Atom format) and calls the appropriate helper methodfor each.

Next, add the parsing code for each method as follows:

- (void)parseRss:(GDataXMLElement *)rootElement entries:(NSMutableArray *)entries {  NSArray *channels = [rootElement elementsForName:@"channel"]; for (GDataXMLElement *channel in channels) {   NSString *blogTitle = [channel valueForChild:@"title"];   NSArray *items = [channel elementsForName:@"item"]; for (GDataXMLElement *item in items) {  NSString *articleTitle = [item valueForChild:@"title"]; NSString *articleUrl = [item valueForChild:@"link"]; NSString *articleDateString = [item valueForChild:@"pubDate"]; NSDate *articleDate = nil;  RSSEntry *entry = [[[RSSEntry alloc] initWithBlogTitle:blogTitle articleTitle:articleTitle articleUrl:articleUrl articleDate:articleDate] autorelease]; [entries addObject:entry];  } } } - (void)parseAtom:(GDataXMLElement *)rootElement entries:(NSMutableArray *)entries {  NSString *blogTitle = [rootElement valueForChild:@"title"];   NSArray *items = [rootElement elementsForName:@"entry"]; for (GDataXMLElement *item in items) {  NSString *articleTitle = [item valueForChild:@"title"]; NSString *articleUrl = nil; NSArray *links = [item elementsForName:@"link"]; for(GDataXMLElement *link in links) { NSString *rel = [[link attributeForName:@"rel"] stringValue]; NSString *type = [[link attributeForName:@"type"] stringValue]; if ([rel compare:@"alternate"] == NSOrderedSame && [type compare:@"text/html"] == NSOrderedSame) { articleUrl = [[link attributeForName:@"href"] stringValue]; } }  NSString *articleDateString = [item valueForChild:@"updated"]; NSDate *articleDate = nil;  RSSEntry *entry = [[[RSSEntry alloc] initWithBlogTitle:blogTitle articleTitle:articleTitle articleUrl:articleUrl articleDate:articleDate] autorelease]; [entries addObject:entry];

Page 12: How to Make a Simple RSS Reader iPhone App Tutorial

2/3/2016 How to Make a Simple RSS Reader iPhone App Tutorial

http://www.raywenderlich.com/2636/rss­reader­tutorial­for­ios­how­to­make­a­simple­rss­reader­iphone­app 12/18

  }  }

These functions are fairly simple, and pull out the data we’re looking for in each entry according to the RSS and Atomformats. If you’re unsure how this works, you might want to review the RSS and Atom formats, and take a look at the HowTo Read and Write XML Documents with GDataXML tutorial, which covers the API in more detail.

Note that right now the dates aren’t being parsed and are just being set to nil. We’ll get to that later.

Compile and run the code, and now you should see articles fly into the screen for all of the blogs!

Sorting by DateMost of the time when you’re looking at RSS entries, you want to see them listed in the order of the date the articles wereposted, so you make sure you’re reading recent articles. So let’s get that working in this iPhone app tutorial!

It turns out that converting date strings in RSS/Atom is non­trivial, due to the different formats dates can potentially bewritten in. Luckily, Michael Waterfall has written a helper class that solves the problem! In fact, he’s written an entire RSSfeed parser, but we’re obviously not going to use that here since we’re taking the approach of writing it ourselves.

But we do need that date converting class of his. So add it to your project by taking the following steps:

1. Download MWFeedParser

2. Drag Classes\NSDate+InternetDateTime.h/m to your Classes folder. Make sure “Copy items into destinationgroup’s folder (if needed)” is checked, and click Add.

Page 13: How to Make a Simple RSS Reader iPhone App Tutorial

2/3/2016 How to Make a Simple RSS Reader iPhone App Tutorial

http://www.raywenderlich.com/2636/rss­reader­tutorial­for­ios­how­to­make­a­simple­rss­reader­iphone­app 13/18

Then switch to RootViewController.m and make the following changes:

// Add to top of file#import "NSDate+InternetDateTime.h" // Replace line that sets articleDate to nil in parseRssNSDate *articleDate = [NSDate dateFromInternetDateTimeString:articleDateString formatHint:DateFormatHintRFC822]; // Replace line that sets articleDate to nil ni parseAtomNSDate *articleDate = [NSDate dateFromInternetDateTimeString:articleDateString formatHint:DateFormatHintRFC3339];

Compile and run the code, and you’ll see that the dates show up OK now! Now all you need to do is sort them.

But how do you do that? I’m sure many of you are familiar with sorting arrays using methods such assortedArrayUsingDescriptor or sortedArrayUsingComparator, but what should you do if you want to simply insert a newitem into the appropriate spot for an already­sorted array?

Well, there’s no built­in way to do this with the iOS API, but we can add a helper method to NSArray to make this a loteasier. Basically, it will use binary searching to find the appropriate spot inside a sortes NSArray to insert a new element,based on a passed­in comparator block.

So let’s add this helper method by creating a category on NSArray. Select the Classes group, go to File\New File,choose iOS\Cocoa Touch Class\Objective­C class, and click Next. Name the class NSArray+Extras.m, make sure “Alsocreate NSArray+Extras.h” is checked, and click Finish.

Replace NSArray+Extras.h with the following:

//// Adapted from: http://blog.jayway.com/2009/03/28/adding-sorted-inserts-to-uimutablearray/// #import <Foundation/Foundation.h> @interface NSArray (Extras) typedef NSInteger (^compareBlock)(id a, id b); -(NSUInteger)indexForInsertingObject:(id)anObject sortedUsingBlock:(compareBlock)compare; @end

And NSArray+Extras.m with the following:

//// Adapted from: http://blog.jayway.com/2009/03/28/adding-sorted-inserts-to-uimutablearray/// #import "NSArray+Extras.h" @implementation NSArray (Extras) -(NSUInteger)indexForInsertingObject:(id)anObject sortedUsingBlock:(compareBlock)compare { NSUInteger index = 0; NSUInteger topIndex = [self count]; while (index < topIndex) { NSUInteger midIndex = (index + topIndex) / 2; id testObject = [self objectAtIndex:midIndex];

Page 14: How to Make a Simple RSS Reader iPhone App Tutorial

2/3/2016 How to Make a Simple RSS Reader iPhone App Tutorial

http://www.raywenderlich.com/2636/rss­reader­tutorial­for­ios­how­to­make­a­simple­rss­reader­iphone­app 14/18

if (compare(anObject, testObject) < 0) { index = midIndex + 1; } else { topIndex = midIndex; } } return index;} @end

If you read through indexForInsertingObject, you can see that it compares the current object to the middle of the array,and recurses in either the top half or bottom half, depending on the sort result. This is a fast way to find the appropriatespot to insert an object into a sorted array.

You’ll see that we set up the method so you can pass in a block of code that performs the comparison as a parameter, tomake it nice and easy to use as well.

So let’s give it a try! Open RootViewController.m and make the following changes:

// Add to top of file#import "NSArray+Extras.h" // In requestFinished, replace the line that sets insertIdx to 0 with thisint insertIdx = [_allEntries indexForInsertingObject:entry sortedUsingBlock:^(id a, id b) { RSSEntry *entry1 = (RSSEntry *) a; RSSEntry *entry2 = (RSSEntry *) b; return [entry1.articleDate compare:entry2.articleDate];}];

Compile and run the code, and now the list of RSS entries should be sorted by date, and dynamically update as newarticles come in!

Page 15: How to Make a Simple RSS Reader iPhone App Tutorial

2/3/2016 How to Make a Simple RSS Reader iPhone App Tutorial

http://www.raywenderlich.com/2636/rss­reader­tutorial­for­ios­how­to­make­a­simple­rss­reader­iphone­app 15/18

Adding a Web ViewJust one more finishing touch for this simple RSS reader – adding a web view to view a selected article! So let’s quicklyadd this.

Select the Classes group in XCode, and go to File\New File, choose iOS\Cocoa Touch Class\UIViewController class,make sure “With XIB for User Interface” is checked but the others are not checked, and click Next. Name the classWebViewController.m, make sure “Also create WebViewController.h” is checked, and click Finish.

Open WebViewController.m and modify it to look like the following:

#import <UIKit/UIKit.h> @class RSSEntry; @interface WebViewController : UIViewController { UIWebView *_webView; RSSEntry *_entry;} @property (retain) IBOutlet UIWebView *webView;@property (retain) RSSEntry *entry; @end

This just adds an outlet for the web view we’re about to add in Interface Builder, and a property to keep track of the RSSEntry to display.

Page 16: How to Make a Simple RSS Reader iPhone App Tutorial

2/3/2016 How to Make a Simple RSS Reader iPhone App Tutorial

http://www.raywenderlich.com/2636/rss­reader­tutorial­for­ios­how­to­make­a­simple­rss­reader­iphone­app 16/18

Save your file. Then double click on WebViewController.xib and drag a web view from the library into the middle of theview so it fills up the whole area. Select the web view, and in the attributes inspector make sure “Scales pages to fit” ischecked. Finally, control­click File’s Owner, drag a line to the Web View, and connect it to the webView outlet.

Next make the following changes to WebViewController.m:

// At top of file#import "RSSEntry.h" // Under @implementation@synthesize webView = _webView;@synthesize entry = _entry; // Add new methods- (void)viewWillAppear:(BOOL)animated {  NSURL *url = [NSURL URLWithString:_entry.articleUrl]; [_webView loadRequest:[NSURLRequest requestWithURL:url]]; } - (void)viewWillDisappear:(BOOL)animated {  [_webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"about:blank"]]]; } // Add inside dealloc[_entry release];_entry = nil;[_webView release];

Page 17: How to Make a Simple RSS Reader iPhone App Tutorial

2/3/2016 How to Make a Simple RSS Reader iPhone App Tutorial

http://www.raywenderlich.com/2636/rss­reader­tutorial­for­ios­how­to­make­a­simple­rss­reader­iphone­app 17/18

_webView = nil;

These methods simply display the appropriate URL in viewWillAppear, and clear the screen on viewWillDisappear.

Next add a new instance variable and property for the WebViewController in RootViewController.h:

// Before @interface@class WebViewController; // Inside @interfaceWebViewController *_webViewController; // After @interface@property (retain) WebViewController *webViewController;

Then make the following changes to RootViewController.m:

// At top of file#import "WebViewController.h" // Under @implementation@synthesize webViewController = _webViewController; // Replace tableView:didSelectRowAtIndexPath with the following- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {  if (_webViewController == nil) { self.webViewController = [[[WebViewController alloc] initWithNibName:@"WebViewController" bundle:[NSBundle mainBundle]] autorelease]; } RSSEntry *entry = [_allEntries objectAtIndex:indexPath.row]; _webViewController.entry = entry; [self.navigationController pushViewController:_webViewController animated:YES]; } // In didReceiveMemoryWarningself.webViewController = nil; // In dealloc[_webViewController release];_webViewController = nil;

Compile and run your code, and you should now be able to click a post to see an article!

Page 18: How to Make a Simple RSS Reader iPhone App Tutorial

2/3/2016 How to Make a Simple RSS Reader iPhone App Tutorial

http://www.raywenderlich.com/2636/rss­reader­tutorial­for­ios­how­to­make­a­simple­rss­reader­iphone­app 18/18

Where To Go From Here?Here is a sample project with all of the code we’ve developed in the above iPhone app tutorial.

I hope that this article was an interesting and practical example of reading and working with networked data in iOS, andhopefully covered some new and interesting things along the way! If you have any questions, thoughts, or suggestionsfor improvement, please let me know!

Ray WenderlichRay is part of a great team ­ the raywenderlich.com team, a group of over 100developers and editors from across the world. He and the rest of the team arepassionate both about making apps and teaching others the techniques to make them.

When Ray’s not programming, he’s probably playing video games, role playing games,or board games.