Parsing XML on iphone SDK

I wrote some code, most of which was taken from textbooks, etc., but not sure if it is 100%. The code works, but I think it is a little long and has memory leaks.

So, three questions:

  • Can I clean it? Easier to understand?
  • How can I fix 'if (indexPath.section == 1) theRow + = 6;' bit for dynamic?
  • Memory leaks, how can I sort if they need to be sorted? (Newbie ...)

Any feedback / pointers / help is more than welcome ...

#import "InfoViewController.h" @implementation InfoViewController - (void)parseXMLFileAtURL:(NSString *)URL { sections = [[NSMutableArray alloc] init]; secItems = [[NSMutableArray alloc] init]; //you must then convert the path to a proper NSURL or it won't work NSURL *xmlURL = [NSURL URLWithString:URL]; rssParser = [[NSXMLParser alloc] initWithContentsOfURL:xmlURL]; // Set self as the delegate of the parser so that it will receive the parser delegate methods callbacks. [rssParser setDelegate:self]; // Depending on the XML document you're parsing, you may want to enable these features of NSXMLParser. [rssParser setShouldProcessNamespaces:NO]; [rssParser setShouldReportNamespacePrefixes:NO]; [rssParser setShouldResolveExternalEntities:NO]; [rssParser parse]; } - (void)parserDidStartDocument:(NSXMLParser *)parser { [activityIndicator startAnimating]; [activityIndicator addSubview]; } - (void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError { NSString * errorString = [NSString stringWithFormat:@"Unable to download story feed from web site (Error code %i )", [parseError code]]; NSLog(@"error parsing XML: %@", errorString); UIAlertView * errorAlert = [[UIAlertView alloc] initWithTitle:@"Error loading content" message:errorString delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil]; [errorAlert show]; } - (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict{ currentElement = [elementName copy]; if ([elementName isEqualToString:@"title"]) { // clear out our story item caches... currentTitle = [[NSMutableString alloc] init]; } if ([elementName isEqualToString:@"section"]) { //item = [[NSMutableDictionary alloc] init]; item = [[NSMutableDictionary alloc] init]; currentSection = [[NSMutableString alloc] init]; } } - (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName{ if ([elementName isEqualToString:@"section"]) { // save values to an item, then store that item into the array... [item setObject:currentSection forKey:@"name"]; [item setObject:[NSNumber numberWithInt:itemsCount] forKey:@"itemsCount"]; [sections addObject:[item copy]]; itemsCount = 0; } if ([elementName isEqualToString:@"title"]) { // save values to an item, then store that item into the array... [item setObject:currentTitle forKey:@"title"]; itemsCount = itemsCount + 1; [secItems addObject:[item copy]]; } } - (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string{ // save the characters for the current item... if ([currentElement isEqualToString:@"name"]) { [currentSection appendString:string]; } else if ([currentElement isEqualToString:@"title"]) { [currentTitle appendString:string]; } else if ([currentElement isEqualToString:@"description"]) { [currentSummary appendString:string]; } else if ([currentElement isEqualToString:@"pubDate"]) { [currentDate appendString:string]; } } - (void)parserDidEndDocument:(NSXMLParser *)parser { [activityIndicator stopAnimating]; [activityIndicator removeFromSuperview]; [dataTable reloadData]; } - (void)viewDidAppear:(BOOL)animated { [super viewDidAppear:animated]; if ([sections count] == 0) { NSString * path = @"http://www.website.com/_dev/info.xml"; [self parseXMLFileAtURL:path]; } } #pragma mark - #pragma mark Table view data source - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { // Return the number of sections. return [sections count]; } - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section { return [[sections objectAtIndex: section] objectForKey: @"name"]; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return [[[sections objectAtIndex: section] objectForKey: @"itemsCount"] intValue]; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell"]; if(cell == nil){ cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"cell"]; } int theRow = indexPath.row; /* if(indexPath.section >= 1){ int oldSection = indexPath.section - 1; int prevRows = prevRows + [[[sections objectAtIndex: oldSection] objectForKey: @"itemsCount"] intValue]; theRow += prevRows; } */ if (indexPath.section == 1) theRow += 6; if (indexPath.section == 2) theRow += 8; if (indexPath.section == 3) theRow += 14; if (indexPath.section == 4) theRow += 19; if (indexPath.section == 5) theRow += 22; if (indexPath.section == 6) theRow += 23; cell.textLabel.text = [[secItems objectAtIndex:theRow] objectForKey: @"title"]; cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator; return cell; } #pragma mark - #pragma mark Table view delegate - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { // Navigation logic may go here. Create and push another view controller. } #pragma mark - #pragma mark Memory management - (void)didReceiveMemoryWarning { // Releases the view if it doesn't have a superview. [super didReceiveMemoryWarning]; // Relinquish ownership any cached data, images, etc that aren't in use. } - (void)viewDidUnload { // Relinquish ownership of anything that can be recreated in viewDidLoad or on demand. // For example: self.myOutlet = nil; } - (void)dealloc { [super dealloc]; [currentElement release]; [rssParser release]; [sections release]; [item release]; [currentTitle release]; } @end 

The XML feed I am trying to break up into sections and elements:

 <?xml version="1.0" encoding="ISO-8859-1"?> <data> <section> <name>Section 1</name> <item> <title>Title 1</title> <pubDate>1 Sept 2010</pubDate> <detail><![CDATA[Detail text]]></detail> </item> <item> <title>Title 2</title> <pubDate>1 Sept 2010</pubDate> <detail><![CDATA[<Detail text]]></detail> </item> <item> <title>Title 3</title> <pubDate>1 Sept 2010</pubDate> <detail><![CDATA[Detail text]]></detail> </item> <item> <title>Title 4</title> <pubDate>1 Sept 2010</pubDate> <detail><![CDATA[Detail text]]></detail> </item> <item> <title>Title 5</title> <pubDate>1 Sept 2010</pubDate> <detail><![CDATA[Detail text]]></detail> </item> <item> <title>Title 6</title> <pubDate>1 Sept 2010</pubDate> <detail><![CDATA[Detail text]]></detail> </item> </section> <section> <name>Section 2</name> <item> <title>Title 1</title> <pubDate>1 Sept 2010</pubDate> <detail><![CDATA[Detail text]]></detail> </item> <item> <title>Title 2</title> <pubDate>1 Sept 2010</pubDate> <detail><![CDATA[Detail text]]></detail> </item> </section> </data> 
0
source share
2 answers
  • Unfortunately, the NSXMLParser that Apple provides requires at least three functions, as you did. If you want to clear it, consider using a third-party script such as TouchXML or KissXML .

  • As for creating this dynamics, you can put these numbers in an array and read them or change the way you configure the data. Typically, different sections use different data arrays. This takes your theRow variable from the equation. Here is a tutorial that uses several arrays without a dictionary.

  • @JeremyP has some good suggestions. If you are still struggling, build and analyze. This will show you “potentially leaked objects” so you can go through and make sure everything is correctly released.


There are two ways to get around XML trees - this is what you do.

First, the NSXML parser you already have is used. First, create a dictionary containing all the names of elements of a higher level, i.e. Section and element, then add two additional lines to your parser, currentNodeName and parentNodeName. As you repeat, change currentNodeContent to elementName. If elementName is in your dictionary, set parentNodeName to elementName, otherwise leave it as it is.

Using TouchXML requires a bit less code. It works with xpaths, so you can specify / section / name / item / title in the path format. You will probably need to add another loop that counts because you will expand another layer.

+2
source

errorAlert leaks because you are not releasing it.

There are bad leaks with currentElement , currentTitle , item and currentSection , because they are all overwritten in -parserDidStartElement:... without release. You must create save properties for them and only properties (except dealloc) can access them. This will make the problem go away.

+2
source

All Articles