Question

I'm new to this forum and to iPhone development. Due to the fact I know nobody who does iPhone development as well I am stuck and have to ask you guys for a solution.

I am making an application getting the data from an XMLParser, provides the Data to an UITableView in sections (months) within those sections are rows (stages).

When I run my script now it doesn't do this. I know I am close to the solution but I can't see it. And not having somebody to run my script with makes it difficult to debug.

My (Demo)XML File:

<?xml version="1.0" encoding="UTF-8"?>
  <Stages>
    <Month id="1" name="January">
      <Stage id="1">
        <title>Circumference</title>
        <author>Nicholas Nicastro</author>
        <summary>Eratosthenes and the Ancient Quest to Measure the Globe.</summary>
      </Stage>
      <Stage id="2">
        <title>Copernicus Secret</title>
        <author>Jack Repcheck</author>
        <summary>How the scientific revolution began</summary>
      </Stage>
      <Stage id="3">
        <title>Angels and Demons</title>
        <author>Dan Brown</author>
        <summary>Robert Langdon is summoned to a Swiss research facility to analyze a cryptic symbol seared into the chest of a murdered physicist.</summary>
      </Stage>
    </Month>
    <Month id="2" name="February">
      <Stage id="4">
        <title>Keep the Aspidistra Flying</title>
        <author>George Orwell</author>
        <summary>A poignant and ultimately hopeful look at class and society, Keep the Aspidistra Flying pays tribute to the stubborn virtues of ordinary people who keep the aspidistra flying.</summary>
      </Stage>
    </Month>
  </Stages>

My XMLParser class:

#import <UIKit/UIKit.h>
@class DAFAppDelegate, Stage, Month;

@interface XMLParser : NSObject <NSXMLParserDelegate>
{
  NSMutableString *currentElementValue;
  DAFAppDelegate *appDelegate;

  Stage *aStage;
  Month *aMonth;

}

- (XMLParser *) initXMLParser;

@end


#import "XMLParser.h"
#import "DAFAppDelegate.h"
#import "Stage.h"
#import "Month.h"

@implementation XMLParser

- (XMLParser *) initXMLParser
{
  [super init];
  appDelegate = (DAFAppDelegate *)[[UIApplication sharedApplication] delegate];
  return self;
}

- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName attributes:(NSDictionary *)attributeDict
{
  if([elementName isEqualToString:@"Stages"])
  {
      //Initialize the array.
      appDelegate.stages = [[NSMutableArray alloc] init];
  }
  if([elementName isEqualToString:@"Month"])
  {
      //Initialize the Month.
      aMonth = [[Month alloc] init];

      //Extract the attribute here.
      aMonth.name = [attributeDict valueForKey:@"name"];
      aMonth.monthID = [[attributeDict objectForKey:@"id"] integerValue];

      NSLog(@"Reading Month id value :%i", aMonth.monthID);
      NSLog(@"Reading Month name value :%@", aMonth.name);
  }
  if([elementName isEqualToString:@"Stage"])
  {
      //Initialize the Stage.
      aStage = [[Stage alloc] init];

      //Extract the attribute here.
      aStage.stageID = [[attributeDict objectForKey:@"id"] integerValue];

      NSLog(@"Reading id value :%i", aStage.stageID);
  }
  NSLog(@"Processing Element: %@", elementName);
}

- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{ 
  if(!currentElementValue)
  {
      currentElementValue = [[NSMutableString alloc] initWithString:string];
  }
  else
  {
      [currentElementValue appendString:string];
  }
  NSLog(@"Processing Value: %@", currentElementValue);
}

- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
  if([elementName isEqualToString:@"Stages"])
  return;

  //There is nothing to do if we encounter the Stages element here.
  //If we encounter the Stage element howevere, we want to add the book object to the array
  // and release the object.
  if([elementName isEqualToString:@"Month"])
  {
      [appDelegate.stages addObject:aMonth];
      [aMonth release];
      aMonth = nil;
  }
  if([elementName isEqualToString:@"Stage"])
  {
      [aMonth.monthStage addObject:aStage];
      [aStage release];
      aStage = nil;
  }
  else
  {
      [aStage setValue:currentElementValue forKey:elementName];
      [currentElementValue release];
      currentElementValue = nil;
  }
}

- (void) dealloc
{
  [aStage release];
  [aMonth release];
  [currentElementValue release];
  [super dealloc];
}

@end

My RootViewController:

@class DAFAppDelegate;  //Here is my stages mutable array defined

@interface RootViewController : UITableViewController
{
  DAFAppDelegate *appDelegate;
}

@end


#import "RootViewController.h"
#import "DAFAppDelegate.h"
#import "DetailViewController.h"
#import "Stage.h"
#import "Month.h"
#import "AgendaCustomCell.h"

@implementation RootViewController

#pragma mark -
#pragma mark View lifecycle

- (void)viewDidLoad
{
  [super viewDidLoad];
  appDelegate = (DAFAppDelegate *)[[UIApplication sharedApplication] delegate];
  self.title = NSLocalizedString(@"Agenda", @"Master view navigation title");

  UIImageView *image=[[UIImageView alloc]initWithFrame:CGRectMake(0,0,45,45)] ;
  [image setImage:[UIImage imageNamed:@"topBarIcon.png"]];
  [self.navigationController.navigationBar.topItem setTitleView:image];

  self.tableView.backgroundColor = [UIColor clearColor];
}

#pragma mark -
#pragma mark Table view data source

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
  return [appDelegate.stages count];
}

- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
  return @"Month Name";
} 

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
  return [appDelegate.stages count];
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
  static NSString *CellIdentifier = @"AgendaCustomCell";
  AgendaCustomCell *cell = (AgendaCustomCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
  if (cell == nil)
  {
      NSArray *topLevelObject = [[NSBundle mainBundle] loadNibNamed:@"AgendaCustomCell" owner:nil options:nil];
      for (id currentObject in topLevelObject)
      {
        if ([currentObject isKindOfClass:[UITableViewCell class]])
        {
          cell = (AgendaCustomCell *)currentObject;
          break;
        }
      }
  }
  UIView *cellBackView = [[[UIView alloc] initWithFrame:CGRectZero] autorelease];
  cellBackView.backgroundColor = [UIColor colorWithPatternImage: [UIImage imageNamed:@"customCellBg.png"]];
  cell.backgroundView = cellBackView;

  Month *aMonth = [appDelegate.stages objectAtIndex:indexPath.section];
  Stage *aStage = [aMonth.monthStage objectAtIndex:indexPath.row];

  cell.titleLabel.text = aStage.title;
  cell.dateLabel.text = aStage.author;
  cell.nameLabel.text = aStage.summary;
  return cell;
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 60;
}

#pragma mark -
#pragma mark Table view selection

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
  //When a row is selected, create the detail view controller and set its detail item to the item associated with the selected row.
 DetailViewController *detailViewController = [[DetailViewController alloc] initWithStyle:UITableViewStyleGrouped];
 detailViewController.stage = [appDelegate.stages objectAtIndex:indexPath.row];

  // Push the detail view controller.
  [[self navigationController] pushViewController:detailViewController animated:YES];
  [detailViewController release];
}

#pragma mark -
#pragma mark Memory management

- (void)dealloc
{
  [appDelegate release];
  [super dealloc];
}

@end

Please help me out on this one. I have been breaking my head over this one for days now and it is driving me crazy.

Thanks in advanced!!!

Was it helpful?

Solution

The problem might be with your tableView:numberOfRowsInSection: implementation. You have it returning the number of sections, rather than the number of entries in the specified section. Based on your test XML, this will always return 1, which could be the problem you're seeing.

To get the number of entries in a section, based on your sample code I'd do something like this:

Month *aMonth = [appDelegate.stages objectAtIndex:section];
return [aMonth.monthStage count];

This will return the number of entries for a given month.

OTHER TIPS

NSXMLParser works in the background, so I'd say it's possible that when your RootViewController tableView is asking your appDelegate for [appDelegate.stages count]; it may not be ready or finished parsing the XML at that point.

Look at implementing 'parserDidEndDocument:' delegate call back and load the UITableView data after that call back.

Load the xml without the singleton object means in your case appDelegate treat as a singleton.... make the property in the appDelegate of NSXMLParser, and when you intiate the object set to autorelease not in dealloc.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top