Jumhyn Jumhyn - 1 year ago 30
Objective-C Question

Creating NSDictionary from RSS Feed?

I Googled around a bit, but can't find a whole lot on the subject. I have the URL to an RSS feed, and I want to know how to go about getting that content into my app in the form of an NSDictionary. Could I use NSData's initWithContentsOfURL?

Answer Source

You need two things:

  1. retrieving the content of your RSS in XML
  2. parsing the retrieved XML file

Retrieving the RSS feed data

The Apple documentation contains many examples of retrieving data from a web service using NSURLConnection. Lots of examples are available on the Apple documentation. Here are the main points though.

First you need to initialize your connection with a proper URL and initiate it. The code below shows how to do this:

// Create a URL for your rss feed
NSURL *url = [NSURL URLWithString:@"http://yourrssfeedurl"];    
// Create a request object with that URL
NSURLRequest *request = [NSURLRequest requestWithURL:url 

// Clear the existing connection if there is one
if (connectionInProgress) {
    [connectionInProgress cancel];
    [connectionInProgress release];

// Instantiate the object to hold all incoming data
[receivedData release];
receivedData = [[NSMutableData alloc] init];

// Create and initiate the connection - non-blocking
connectionInProgress = [[NSURLConnection alloc] initWithRequest:request 

In this code the connectionInProgress is an ivar of type NSURLConnection defined in the class performing the connection.

Then you need to implement the NSURLConnectionDelegate methods:

// This method is called everytime the current connection receives data
-(void) connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
    [receivedData appendData:data];

// This method is called once the connection is completed
-(void) connectionDidFinishLoading:(NSURLConnection *)connection
    NSString *xmlCheck = [[[NSString    alloc] initWithData:receivedData
                                        encoding:NSUTF8StringEncoding] autorelease];
    NSLog(@"xmlCheck = %@", xmlCheck);

    // Release our memory: we're done!
    [connectionInProgress release];
    connectionInProgress = nil;

    [receivedData release];
    receivedData = nil; 

// This method is called when there is an error
-(void) connection:(NSURLConnection *)connection 
  didFailWithError:(NSError *)error
    [connectionInProgress release];
    connectionInProgress = nil;

    [receivedData release];
    receivedData = nil;

    NSString *errorString = [NSString stringWithFormat:@"Fetch failed: %@", [error localizedDescription]];

    NSLog(@"%@", errorString);

In the code above receivedData is an ivar of type NSMutableData defined in the class performing the connection.

Parsing XML

Parsing the xml file you have just retrieved is quite straightforward using the NSXMLParser class.

The class calling the parser needs to implement the NSXMParserDelegate protocol. This is done like this in the .h of the object dealing with the parsing (DataManager in this example):

@interface DataManager : _DataManager <NSXMLParserDelegate>

And in the implementation file you need to implement at least the following methods:

The method called every time a new XML tag if found in your xml file. This is typically where you will either define new objects so you can set their properties as they are being read or where you will clear the string used to store the characters found in your XML file.

- (void)parser:(NSXMLParser *)parser 
didStartElement:(NSString *)elementName 
  namespaceURI:(NSString *)namespaceURI 
 qualifiedName:(NSString *)qualifiedName 
    attributes:(NSDictionary *)attributeDict

The method called every time the parser finds characters in your file (not elements names). Here currentElementString is an ivar of type 'NSMutabletring'.

- (void)parser:(NSXMLParser *)parser 
foundCharacters:(NSString *)string
    [currentElementString appendString:string];

Last the method called whenever reading of an element is completed. This is typically where you would store any completely parsed element into your data structure hierarchy (dictionary or otherwise):

- (void)parser:(NSXMLParser *)parser 
 didEndElement:(NSString *)elementName 
  namespaceURI:(NSString *)namespaceURI 
 qualifiedName:(NSString *)qName

The parsing starts when you tell the parser to do so. It's a synchronous call, i.e. it will block you application until the parsing is over. Here is how you define the parser and call it:

// Create an XML parser with the data received from the web service
NSXMLParser *parser = [[NSXMLParser alloc] initWithData:data];

// Give the parser  delegate
[parser setDelegate:self];

// Tell the parser to start parsing - The complete document will be parsed and the delegate to 
// of NSXMLParser will get all of its delegate messages sent to it before this line finishes
// execution. The parser is blocking.
[parser parse];

// Parser has finished its job, release it
[parser release];

One last piece of advice. Typically you will have a big if...else if statement in the didStartElement and didEndElement methods where you need to compare the elementName to the names of the elements you expect. It is advisable to use constant string definitions which you can use in both methods as opposed to typing the strings in the methods. This means this:

static NSString *ks_ElementName1 = @"ElementName1";

should be declared and used in both didStartElement and didEndElement methods to identify "ElementName1" in your XML.

VoilĂ , good luck with your app.