Everything works fine when the view that holds my table is the main (first) view.
However, when it's not the first view and I switch into that view, my table does not load data and I get an empty table.
Using NSLog I can tell that the program is not invoking numberOfRowsInSection and cellForRowAtIndexPath.
I have <UITableViewDataSource, UITableViewDelegate>, IBOutlet UITableview *tableView all declared. They are also connected in the InterfaceBuilder.
I tried using viewWillAppear and [tableView reloadData] but that did not help.
I'm new to iPhone development and your help is appreciated!
UPDATE:
I tried [tableView reloadData] but nothing happened.
I'm not releasing tableView anywhere but dealloc.
Here is some code:
appDelegate
//
// tpbAppDelegate.m
// tpb
#import "listController.h"
#import "tpbAppDelegate.h"
#import "tpbViewController.h"
#implementation tpbAppDelegate
#synthesize window;
#synthesize viewController;
#synthesize navController;
#synthesize toolbar;
#synthesize btnMyLoc;
#synthesize places; //array that holds data from the XML file
- (void)applicationDidFinishLaunching:(UIApplication *)application {
//add places into an array that can be used by other views (Table)
rssList = [[NSMutableArray alloc] initWithCapacity:1];
NSString *paths = [[NSBundle mainBundle] resourcePath];
NSString *xmlFile = [paths stringByAppendingPathComponent:#"tourplay.xml"];
NSURL *xmlURL = [NSURL fileURLWithPath:xmlFile isDirectory:NO];
NSLog(#"DATA URL: %#", xmlURL);
NSXMLParser *firstParser = [[NSXMLParser alloc] initWithContentsOfURL:xmlURL];
[firstParser setDelegate:self];
[firstParser parse];
// Resize window for toolbar:
CGRect frame = viewController.view.frame;
frame.size.height -= toolbar.frame.size.height;
viewController.view.frame = frame;
//[window addSubview:viewController.view];
navController.viewControllers = [NSArray arrayWithObject:viewController];
navController.view.frame = frame;
[window addSubview:navController.view];
[window makeKeyAndVisible];
}
- (IBAction)showList:(id)sender{
//Switch to table view on segment control change
UISegmentedControl *segmentControl = (UISegmentedControl *)sender;
NSString *curSelection = [NSString stringWithFormat:#"%d", [segmentControl selectedSegmentIndex]];
//[segmentControl titleForSegmentAtIndex: [segmentControl selectedSegmentIndex]]];
NSLog(#"pressed button %#", curSelection);
if ([curSelection isEqualToString:#"1"]){
NSLog(#"TABLE SELECTED");
listController *listTable = [[listController alloc] init];
[navController pushViewController:listTable animated:YES]; //SWITCH TO TABLE VIEW (listController)
} else {
tpbViewController *tpb = [[tpbViewController alloc] init];
NSLog(#"MAP SELECTED");
[navController pushViewController:tpb animated:YES];
}
}
#pragma mark Praser Methods
//Parse XML into an array
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName attributes:(NSDictionary *)attributeDict {
//NSLog(#"Started parsing");
if ([elementName compare:#"tour_point"] == NSOrderedSame) {
[self.places addObject:[[NSDictionary alloc] initWithObjectsAndKeys:
//[attributeDict objectForKey:#"tour_point_id"],#"tour_point_id",
[attributeDict objectForKey:#"name"],#"name",
[attributeDict objectForKey:#"tour_html"],#"tour_html",
[attributeDict objectForKey:#"audio_src"],#"audio_src",
nil]];
} else if ([elementName compare:#"title"] == NSOrderedSame) {
titlename = (NSString *)[attributeDict objectForKey:#"titlename"];
NSLog(#"Done parsing %# points", titlename);
}
}
- (void)parserDidEndDocument:(NSXMLParser *)parser {
NSLog(#"Parser end");
[parser release];
}
- (void)dealloc {
[viewController release];
[rssList release];
[places release];
[toolbar release];
[window release];
[super dealloc];
}
#end
listController.h - table class
#import <UIKit/UIKit.h>
#interface listController : UIViewController <UITableViewDataSource, UITableViewDelegate> {
UITableView *tableView;
NSMutableArray *places;
NSString *titlename;
}
#property (nonatomic, retain) IBOutlet UITableView *tableView;
#end
listController.m - table implemenation
//
// listController.m
// tpb
//
//
#import "listController.h"
#import "tpbAppDelegate.h"
#implementation listController
#synthesize tableView;
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
//- (void)viewWillAppear {
tpbAppDelegate *delegate = (tpbAppDelegate *)[[UIApplication sharedApplication] delegate];
places = delegate.places;
NSLog(#"Loaded table view");
[super viewDidLoad];
// [tableView reloadSectionIndexTitles];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tv {
NSLog(#"Number of secions");
return 1;
}
- (NSInteger)tableView:(UITableView *)tv numberOfRowsInSection:(NSInteger)section {
NSLog(#"GETTING COUNT");
return [places count];
}
- (UITableViewCell *)tableView:(UITableView *)tv cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSLog(#"Assigning Cells");
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tv dequeueReusableCellWithIdentifier:CellIdentifier];
if (nil == cell) {
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease];
}
cell.textLabel.text = [[places objectAtIndex:indexPath.row] objectForKey:#"name"];
//NSLog(#"count %#", [[places objectAtIndex:indexPath.row] objectForKey:#"name"]);
//cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
return cell;
}
- (void)tableView:(UITableView *)tv didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSLog(#"ROW clicked");
[tv deselectRowAtIndexPath:indexPath animated:YES];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
- (void)viewDidUnload {
NSLog(#"Unloaded tableview");
}
- (void)dealloc {
[tableView release];
[places release];
[super dealloc];
}
#end
-- So far, I know that viewDidLoad loads, but the table meathods such as cellRowAtIndexPath are not invoked.
This problem happens when you do not link the datasource and delegate of table view to the file's owner in the interface builder. Cross check once again in the interface builder see the connections for datasource and delegate of tableview are properly made with files owner and you have not mistakenly linked them with view.
Besides tell one thing more if
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
is getting called. If it is then you have passed 0 in this. Well a '0' is not acceptable from iphone-sdk-3.0 and later.
Thanks,
Madhup
- (IBAction)showList:(id)sender{
//Switch to table view on segment control change
UISegmentedControl *segmentControl = (UISegmentedControl *)sender;
NSString *curSelection = [NSString stringWithFormat:#"%d", [segmentControl selectedSegmentIndex]];
//[segmentControl titleForSegmentAtIndex: [segmentControl selectedSegmentIndex]]];
NSLog(#"pressed button %#", curSelection);
if ([curSelection isEqualToString:#"1"]){
NSLog(#"TABLE SELECTED");
listController *listTable = [[listController alloc] init];
//Try this
listTable.places = self.places; // set the array contents here and check
[navController pushViewController:listTable animated:YES]; //SWITCH TO TABLE VIEW (listController)
} else {
tpbViewController *tpb = [[tpbViewController alloc] init];
NSLog(#"MAP SELECTED");
[navController pushViewController:tpb animated:YES];
}
}
Dont forget to write the accessors in ListController for places array. And let me know what happens.
When you go to display your tableview, call the reloadData method on it; if your datasource/delegate is assigned to the correct object then that will trigger the table view to ask the datasource/delegate for its cells, and it should display at that point.
Related
I'm trying to use the MWFeedParser library in my app. On my homescreen, I have a view controller named NewsViewController.
In the MWFeedParser library, the root view controller is called RootViewController. I've tried to copy all the code from the RootViewController into the NewsViewController .H + .M and in IB I've linked the tableview to "dataSource" and "delegate". But when my app starts the tableview is empty.
Here's how to code looks like:
.H:
#import <UIKit/UIKit.h>
#import "MWFeedItem.h"
#import "MWFeedParser.h"
#interface NewsViewController : UITableViewController <MWFeedParserDelegate, UITableViewDelegate, UITableViewDataSource> {
// Parsing
MWFeedParser *feedParser;
NSMutableArray *parsedItems;
// Displaying
NSArray *itemsToDisplay;
NSDateFormatter *formatter;
IBOutlet UITableView *tableView;
}
// Properties
#property (nonatomic, retain) NSArray *itemsToDisplay;
#property (nonatomic, retain) IBOutlet UITableView *tableView;
-(IBAction)goHome;
#end
.M:
#import "NSString+HTML.h"
#import "MWFeedParser.h"
#import "DetailTableViewController.h"
#implementation NewsViewController
#synthesize itemsToDisplay, tableView;
#pragma mark -
#pragma mark View lifecycle
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
self.title = NSLocalizedString(#"News", #"News");
self.tabBarItem.image = [UIImage imageNamed:#"icon_news"]; }
return self;
}
- (void)viewDidLoad
{
label.shadowOffset = CGSizeMake(0.0f, 1.0f);
label.textColor = [UIColor colorWithRed:0xB3/249.0 green:0xB3/252.0 blue:0xB3/253.0 alpha:1];
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
// Date
// Setup
formatter = [[NSDateFormatter alloc] init];
[formatter setDateStyle:NSDateFormatterShortStyle];
[formatter setTimeStyle:NSDateFormatterShortStyle];
parsedItems = [[NSMutableArray alloc] init];
self.itemsToDisplay = [NSArray array];
// Refresh button
self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemRefresh
target:self
action:#selector(refresh)];
// Parse
NSURL *feedURL = [NSURL URLWithString:#"http://www.mywebsite.com/feed/"];
feedParser = [[MWFeedParser alloc] initWithFeedURL:feedURL];
feedParser.delegate = self;
feedParser.feedParseType = ParseTypeFull; // Parse feed info and all items
feedParser.connectionType = ConnectionTypeAsynchronously;
[feedParser parse];
UIImage *someImage = [UIImage imageNamed:#"back_active1#2x.png"];
[button setBackgroundImage:someImage forState:UIControlStateHighlighted];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void)viewDidAppear:(BOOL)animated {
static BOOL first = YES;
if (first) {
UIViewController *popup = [[Home1ViewController alloc] initWithNibName:#"Home1ViewController" bundle:nil];
[self presentViewController:popup animated:NO completion:nil];
first = NO;
}
}
#pragma mark -
#pragma mark Parsing
// Reset and reparse
- (void)refresh {
self.title = #"Refreshing...";
[parsedItems removeAllObjects];
[feedParser stopParsing];
[feedParser parse];
self.tableView.userInteractionEnabled = NO;
self.tableView.alpha = 0.3;
}
- (void)updateTableWithParsedItems {
self.itemsToDisplay = [parsedItems sortedArrayUsingDescriptors:
[NSArray arrayWithObject:[[NSSortDescriptor alloc] initWithKey:#"date"
ascending:NO]]];
self.tableView.userInteractionEnabled = YES;
self.tableView.alpha = 1;
[self.tableView reloadData];
}
#pragma mark -
#pragma mark MWFeedParserDelegate
- (void)feedParserDidStart:(MWFeedParser *)parser {
NSLog(#"Started Parsing: %#", parser.url);
}
- (void)feedParser:(MWFeedParser *)parser didParseFeedInfo:(MWFeedInfo *)info {
NSLog(#"Parsed Feed Info: “%#”", info.title);
self.title = info.title;
}
- (void)feedParser:(MWFeedParser *)parser didParseFeedItem:(MWFeedItem *)item {
NSLog(#"Parsed Feed Item: “%#”", item.title);
if (item) [parsedItems addObject:item];
}
- (void)feedParserDidFinish:(MWFeedParser *)parser {
NSLog(#"Finished Parsing%#", (parser.stopped ? #" (Stopped)" : #""));
[self updateTableWithParsedItems];
}
- (void)feedParser:(MWFeedParser *)parser didFailWithError:(NSError *)error {
NSLog(#"Finished Parsing With Error: %#", error);
if (parsedItems.count == 0) {
self.title = #"Failed"; // Show failed message in title
} else {
// Failed but some items parsed, so show and inform of error
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Parsing Incomplete"
message:#"There was an error during the parsing of this feed. Not all of the feed items could parsed."
delegate:nil
cancelButtonTitle:#"Dismiss"
otherButtonTitles:nil];
[alert show];
}
[self updateTableWithParsedItems];
}
#pragma mark -
#pragma mark Table view data source
// Customize the number of sections in the table view.
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
// Customize the number of rows in the table view.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return itemsToDisplay.count;
}
// Customize the appearance of table view cells.
- (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];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
// Configure the cell.
MWFeedItem *item = [itemsToDisplay objectAtIndex:indexPath.row];
if (item) {
// Process
NSString *itemTitle = item.title ? [item.title stringByConvertingHTMLToPlainText] : #"[No Title]";
NSString *itemSummary = item.summary ? [item.summary stringByConvertingHTMLToPlainText] : #"[No Summary]";
// Set
cell.textLabel.font = [UIFont boldSystemFontOfSize:15];
cell.textLabel.text = itemTitle;
NSMutableString *subtitle = [NSMutableString string];
if (item.date) [subtitle appendFormat:#"%#: ", [formatter stringFromDate:item.date]];
[subtitle appendString:itemSummary];
cell.detailTextLabel.text = subtitle;
}
return cell;
}
#pragma mark -
#pragma mark Table view delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
// Show detail
DetailTableViewController *detail = [[DetailTableViewController alloc] initWithStyle:UITableViewStyleGrouped];
detail.item = (MWFeedItem *)[itemsToDisplay objectAtIndex:indexPath.row];
[self.navigationController pushViewController:detail animated:YES];
// Deselect
[self.tableView deselectRowAtIndexPath:indexPath animated:YES];
}
#end
what you do is in feedparserDidFinish method , try to reload table....like below...
- (void)feedParserDidFinish:(MWFeedParser *)parser {
NSLog(#"Finished Parsing%#", (parser.stopped ? #" (Stopped)" : #""));
[self.tableView reloadData];
}
let me know it is working or not!!!!!
Happy Coding!!!!!!!
I trying to use the MWFeedParser library. I think the problem is that I want to use a view controller with a table view to display the news. Now there comes nothing up in my table view when launching the app. The code for the news view controller looks like this:
.H:
#import "MWFeedItem.h"
#import "MWFeedParser.h"
#interface NewsViewController : UIViewController <MWFeedParserDelegate> {
IBOutlet UILabel *label;
// Parsing
MWFeedParser *feedParser;
NSMutableArray *parsedItems;
// Displaying
NSArray *itemsToDisplay;
NSDateFormatter *formatter;
IBOutlet UITableView *tableView;
}
// Properties
#property (nonatomic, retain) NSArray *itemsToDisplay;
#property (nonatomic, retain) IBOutlet UITableView *tableView;
#end
.M:
#import "NSString+HTML.h"
#import "MWFeedParser.h"
#import "DetailTableViewController.h"
#implementation NewsViewController
#synthesize itemsToDisplay, tableView;
#pragma mark -
#pragma mark View lifecycle
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
self.title = NSLocalizedString(#"News", #"News");
self.tabBarItem.image = [UIImage imageNamed:#"icon_news"]; }
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
// Date
// Setup
self.title = #"News";
formatter = [[NSDateFormatter alloc] init];
[formatter setDateStyle:NSDateFormatterShortStyle];
[formatter setTimeStyle:NSDateFormatterShortStyle];
parsedItems = [[NSMutableArray alloc] init];
self.itemsToDisplay = [NSArray array];
// Refresh button
self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemRefresh
target:self
action:#selector(refresh)];
// Parse
NSURL *feedURL = [NSURL URLWithString:#"http://www.website.com/feed/"];
feedParser = [[MWFeedParser alloc] initWithFeedURL:feedURL];
feedParser.delegate = self;
feedParser.feedParseType = ParseTypeFull; // Parse feed info and all items
feedParser.connectionType = ConnectionTypeAsynchronously;
[feedParser parse];
UIImage *someImage = [UIImage imageNamed:#"back_active1#2x.png"];
[button setBackgroundImage:someImage forState:UIControlStateHighlighted];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void)viewDidAppear:(BOOL)animated {
static BOOL first = YES;
if (first) {
UIViewController *popup = [[Home1ViewController alloc] initWithNibName:#"Home1ViewController" bundle:nil];
[self presentViewController:popup animated:NO completion:nil];
first = NO;
}
}
#pragma mark -
#pragma mark Parsing
// Reset and reparse
- (void)refresh {
self.title = #"Refreshing...";
[parsedItems removeAllObjects];
[feedParser stopParsing];
[feedParser parse];
/*
self.tableView.userInteractionEnabled = NO;
self.tableView.alpha = 0.3;
*/
}
- (void)updateTableWithParsedItems {
self.itemsToDisplay = [parsedItems sortedArrayUsingDescriptors:
[NSArray arrayWithObject:[[NSSortDescriptor alloc] initWithKey:#"date"
ascending:NO]]];
/* self.tableView.userInteractionEnabled = YES;
self.tableView.alpha = 1;
[self.tableView reloadData];
*/
}
#pragma mark -
#pragma mark MWFeedParserDelegate
- (void)feedParserDidStart:(MWFeedParser *)parser {
NSLog(#"Started Parsing: %#", parser.url);
}
- (void)feedParser:(MWFeedParser *)parser didParseFeedInfo:(MWFeedInfo *)info {
NSLog(#"Parsed Feed Info: “%#”", info.title);
self.title = info.title;
}
- (void)feedParser:(MWFeedParser *)parser didParseFeedItem:(MWFeedItem *)item {
NSLog(#"Parsed Feed Item: “%#”", item.title);
if (item) [parsedItems addObject:item];
}
- (void)feedParserDidFinish:(MWFeedParser *)parser {
NSLog(#"Finished Parsing%#", (parser.stopped ? #" (Stopped)" : #""));
[self updateTableWithParsedItems];
}
- (void)feedParser:(MWFeedParser *)parser didFailWithError:(NSError *)error {
NSLog(#"Finished Parsing With Error: %#", error);
if (parsedItems.count == 0) {
self.title = #"Failed"; // Show failed message in title
} else {
// Failed but some items parsed, so show and inform of error
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Parsing Incomplete"
message:#"There was an error during the parsing of this feed. Not all of the feed items could parsed."
delegate:nil
cancelButtonTitle:#"Dismiss"
otherButtonTitles:nil];
[alert show];
}
[self updateTableWithParsedItems];
}
#pragma mark -
#pragma mark Table view data source
// Customize the number of sections in the table view.
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
// Customize the number of rows in the table view.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return itemsToDisplay.count;
}
// Customize the appearance of table view cells.
- (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];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
// Configure the cell.
MWFeedItem *item = [itemsToDisplay objectAtIndex:indexPath.row];
if (item) {
// Process
NSString *itemTitle = item.title ? [item.title stringByConvertingHTMLToPlainText] : #"[No Title]";
NSString *itemSummary = item.summary ? [item.summary stringByConvertingHTMLToPlainText] : #"[No Summary]";
// Set
cell.textLabel.font = [UIFont boldSystemFontOfSize:15];
cell.textLabel.text = itemTitle;
NSMutableString *subtitle = [NSMutableString string];
if (item.date) [subtitle appendFormat:#"%#: ", [formatter stringFromDate:item.date]];
[subtitle appendString:itemSummary];
cell.detailTextLabel.text = subtitle;
}
return cell;
}
#pragma mark -
#pragma mark Table view delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
// Show detail
DetailTableViewController *detail = [[DetailTableViewController alloc] initWithStyle:UITableViewStyleGrouped];
detail.item = (MWFeedItem *)[itemsToDisplay objectAtIndex:indexPath.row];
[self.navigationController pushViewController:detail animated:YES];
// Deselect
[self->tableView deselectRowAtIndexPath:indexPath animated:YES];
}
#end
In IB, I've dragged a table view onto the view and linked it to dataSource and delegate. But nothing shows up in the table view.
Would really appreciate some answers/ideas!
Thanks.
i think you should uncomment the following line in your "updateTableWithParsedItems" method:
[self.tableView reloadData];
I have a question here: Confusing double free error message/memory leak in iPhone app which I think needs a new question to answer it.
The code I am interested in is in that question but I will re post it here
#import <UIKit/UIKit.h>
#import "MyManager.h"
#interface ListOfCarShares : UITableViewController <NSXMLParserDelegate>
{
NSURLConnection *connection;
NSMutableData *carsharexml;
NSMutableArray *ldestination;
NSMutableArray *ldeparts_from;
NSMutableArray *lcs_id;
NSMutableArray *ltime;
NSMutableString *currentElement;
NSMutableString *tdest;
NSMutableString *tfrom;
NSMutableString *ttime;
NSMutableString *tid;
}
-(void)fetchcarshares;
#property (nonatomic, assign) IBOutlet UITableViewCell *maincell;
#end
#import "ListOfCarShares.h"
#implementation ListOfCarShares
#synthesize maincell;
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
// Custom initialization
}
return self;
}
- (void)parser:(NSXMLParser *)parser
didStartElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI
qualifiedName:(NSString *)qualifiedName
attributes:(NSDictionary *)attributeDict
{
currentElement = [[elementName copy] autorelease];
if ([elementName isEqualToString:#"destination"])
{
//NSLog(#"found current conditions tag it reads %#",currentElement);
tdest = [[NSMutableString alloc] init];
}
if ([elementName isEqualToString:#"departs_from"])
{
tfrom = [[NSMutableString alloc] init];
}
if ([elementName isEqualToString:#"time"])
{
ttime = [[NSMutableString alloc] init];
}
if ([elementName isEqualToString:#"cs_id"])
{
tid = [[NSMutableString alloc] init];
}
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
if ([currentElement isEqualToString:#"destination"])
{
[tdest appendString:string];
}
if ([currentElement isEqualToString:#"departs_from"])
{
[tfrom appendString:string];
}
if ([currentElement isEqualToString:#"time"])
{
[ttime appendString:string];
}
if ([currentElement isEqualToString:#"cs_id"])
{
[tid appendString:string];
}
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
if ([currentElement isEqualToString:#"destination"])
{
[ldestination addObject:tdest];
[tdest release];
}
if ([currentElement isEqualToString:#"departs_from"])
{
[ldeparts_from addObject:tfrom];
[tfrom release];
}
if ([currentElement isEqualToString:#"time"])
{
[ltime addObject:ttime];
[ttime release];
}
if ([currentElement isEqualToString:#"cs_id"])
{
[lcs_id addObject:tid];
[tid release];
}
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
#pragma mark - View lifecycle
- (void)viewDidLoad
{
[super viewDidLoad];
// Uncomment the following line to preserve selection between presentations.
// self.clearsSelectionOnViewWillAppear = NO;
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem;
}
- (void)viewDidUnload
{
[super viewDidUnload];
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
ldestination = [[NSMutableArray alloc] init];
ldeparts_from = [[NSMutableArray alloc] init];
ltime = [[NSMutableArray alloc] init];
lcs_id = [[NSMutableArray alloc] init];
carsharexml = [[NSMutableData alloc] init];
[self fetchcarshares];
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
}
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
[connection release];
[ldestination release];
[ldeparts_from release];
[ltime release];
[lcs_id release]; ///
[carsharexml release];
}
- (void)viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return [ltime count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
//static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:nil];
if (cell == nil)
{
[[NSBundle mainBundle] loadNibNamed:#"carsharecell" owner:self options:nil];
}
// Configure the cell...
cell=maincell;
UILabel *from;
UILabel *dest;
UILabel *time;
from = (UILabel *)[cell viewWithTag:4];
dest = (UILabel *)[cell viewWithTag:5];
time = (UILabel *)[cell viewWithTag:6];
from.text=[ldeparts_from objectAtIndex:indexPath.row];
dest.text=[ldestination objectAtIndex:indexPath.row];
time.text=[ltime objectAtIndex:indexPath.row];
return cell;
}
/*
// Override to support conditional editing of the table view.
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
// Return NO if you do not want the specified item to be editable.
return YES;
}
*/
/*
// Override to support editing the table view.
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle == UITableViewCellEditingStyleDelete) {
// Delete the row from the data source
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
else if (editingStyle == UITableViewCellEditingStyleInsert) {
// Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view
}
}
*/
/*
// Override to support rearranging the table view.
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath
{
}
*/
/*
// Override to support conditional rearranging of the table view.
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath
{
// Return NO if you do not want the item to be re-orderable.
return YES;
}
*/
-(void)fetchcarshares
{
MyManager *sharedManager = [MyManager sharedManager];
NSString *urlString = [NSString stringWithFormat:#"http://url/get.php?username=%#&password=%#",sharedManager.user,sharedManager.passw];
NSURL *url = [NSURL URLWithString:urlString];
NSURLRequest *req = [NSURLRequest requestWithURL:url];
connection = [[NSURLConnection alloc] initWithRequest:req delegate:self startImmediately:YES];
}
-(void) connection:(NSURLConnection *)conn didReceiveData:(NSData *)data
{
[carsharexml appendData:data];
}
-(void) connectionDidFinishLoading:(NSURLConnection *)conn
{
NSString *xmlcheck = [[NSString alloc] initWithData:carsharexml encoding:NSUTF8StringEncoding];
NSLog(#"%#",xmlcheck);
[xmlcheck release];
NSXMLParser *parser = [[NSXMLParser alloc] initWithData: carsharexml];
[parser setDelegate:self];
[parser parse];
[parser release];
[[self tableView] reloadData];
}
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 102;
}
#pragma mark - Table view delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
}
-(void)dealloc
{
[super dealloc];
}
#end
I only have one property defined in the .h file. The people who answered that question seem to think that the reason I am having double free error is due to the fact I don't have #property for my variables.
I have lots of code practically identical to this and I don't have a problem.
My questions are
When should I use a property?
Should I be using properties here and why?
Thanks
You technically only need to use properties for values that are intended to be accessible from other classes, but many find it easier to use (retained) properties for all pointer-type instance variables so that the retaining is a bit more automatic. (And then use self.propertyName = xxx; notation for setting and self.propertyName = nil; for releasing in dealloc.)
Yes, you can do the retains and releases "manually", but it's a hair tedious to do so, and you tend to muck things up when you make "quick edits". The one thing you have to watch out for, though, is assigning a retained (not simply autoretained) value (such as your alloc/init values) to a self.xxx property. This will result in double retain, if you don't mitigate it somehow.
Another thing to do, if you don't use properties, is to always nil a pointer value after you release it. This prevents you from accidentally using the released value and and it prevents you from doing a double release.
(Note that it's in no way "bad programming" to use "lazy" techniques like I described above, vs "perfectly" figuring out everything. About 98% of programming is debugging, and anything you can do to prevent bugs or make them easier to find is goodness.)
(I'll also note that your problem in the above code appears to be mainly that you do not nil thetdest et al pointers after releasing them. And your if tests should likely check to see if the pointer has been nilled before using it.)
Added: Note that the above applies to pre-ARC programs. With ARC the "rules" change substantially.
Properties do a lot of things. At the most superficial level, they let you access your member variables in dotted form. At best, they can be excellent memory management tools (and more).
Let's say you have a variable:
NSNumber * myNumber;
Later in the code, you access it as:
myNumber = [NSNumber numberWithInt: 5];
The problem is that you might lose reference to the previously stored value in myNumber. Possible Memory Leak!! At this point, you don't have a retain on myNumber and it may get dealloc'd before you're done using it.
How can properties help? Let's say you defined a property around it and used synthesize:
In the interface definition:
NSNumber * myNumber;
...
#property (retain, nonatomic) NSNumber * myNumber;
and
In the implementation file:
#synthesize myNumber;
This will create a getter and setter. Meaning... everytime you assign myNumber to something as in:
self.myNumber = newNumber;
the following setter method (created by synthesize directive) gets invoked:
- (NSNumber *) setMyNumber: (NSNumber *) newNumber {
[myNumber release];
myNumber = newNumber;
[myNumber retain];
return newNumber;
}
Here, myNumber gets a retain automatically. This is very tedious to do by hand everytime... as you can see, it's much easier to use properties.
This is still not a perfect solution, though! Why? What if you use the following statement in your implementation:
myNumber = newNumber;
Remember, properties' getter and setter get invoked only if you're using the dotted notation (self.myNumber). So here, using properties has done nothing for us, 'cause we forgot to use them!
This is very common and likely lapse and understandingly frustrating.
So, what's the best way? This is what I recommend (as do countless others):
In the interface class:
NSNumber * _myNumber;
...
#property (retain, nonatomic) NSNumber * myNumber;
In the implementation file:
#synthesize myNumber = _myNumber;
Now, you can access your-number as:
self.myNumber = whateverNewNumber;
But, if you did:
myNumber = whateverNewNumber;
You'll get an error... because myNumber variable just doesn't exist... forcing you to use self.myNumber everytime!
Also, if you do choose to go this route, don't forget the dealloc:
- (void) dealloc {
[_myNumber release];
_myNumber = nil;
}
or more succinct:
- (void) dealloc {
self.myNumber = nil;
}
I load data into my UITableView from an NSXMLParser.
This all works fine but what I would like to implement is some short of activity when the App is loading the XML data, so it all is a bit more friendly for the users.
Some samples I have found still confuse me simply because I did not follow the same way of XMLParser implementation as most same do.
I provide my data here, please give some code samples on how I should put it in my code.
XMLParser.h:
#import <UIKit/UIKit.h>
#class DAFAppDelegate, Stage, Month;
#interface XMLParser : NSObject <NSXMLParserDelegate>
{
NSMutableString *currentElementValue;
DAFAppDelegate *appDelegate;
Stage *aStage;
Month *aMonth;
}
- (XMLParser *) initXMLParser;
+ (NSDate *)dateFromString:(NSString *)dateString;
+ (NSString *)stringFromDate:(NSDate *)stringDate;
#end
XMLParser.m:
#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];
aMonth.stagesPerMonth = [[NSMutableArray 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
{
NSDate* date = [NSDate date];
NSDateFormatter* nsformatter = [[[NSDateFormatter alloc] init] autorelease];
[nsformatter setDateFormat:#"yyyy-MM-dd"];
NSDate* stageDate = [XMLParser dateFromString:aStage.end];
if([elementName isEqualToString:#"Stages"])
{
return;
}
if([elementName isEqualToString:#"Month"])
{
if (!aMonth.stagesPerMonth || aMonth.stagesPerMonth.count)
{
[appDelegate.stages addObject:aMonth];
}
[aMonth release];
aMonth = nil;
}
if([elementName isEqualToString:#"Stage"])
{
NSTimeInterval interval = [date timeIntervalSinceDate:stageDate];
if (interval < 0)
{
[aMonth.stagesPerMonth addObject:aStage];
}
[aStage release];
aStage = nil;
}
else
{
[aStage setValue:currentElementValue forKey:elementName];
[currentElementValue release];
currentElementValue = nil;
}
}
-(void) parserDidStartDocument:(NSXMLParser *)parser
{
NSLog(#"parserDidStartDocument");
}
-(void) parserDidEndDocument: (NSXMLParser *)parser
{
NSLog(#"parserDidEndDocument");
}
+ (NSDate *)dateFromString:(NSString *)dateString
{
NSDateFormatter *nsDateFormatter = [[NSDateFormatter alloc] init];
[nsDateFormatter setDateFormat:#"yyyy-MM-dd'T'HH:mm"];
NSDate *date = [nsDateFormatter dateFromString:dateString];
return date;
[nsDateFormatter release];
}
+ (NSString *)stringFromDate:(NSDate *)stringDate
{
NSDateFormatter *stringDateFormatter = [[NSDateFormatter alloc] init];
NSLocale *nlLocale = [[NSLocale alloc] initWithLocaleIdentifier:#"nl_NL"];
[stringDateFormatter setLocale:nlLocale];
[stringDateFormatter setDateFormat:#"EEE', 'dd MMMM yyyy HH:mma"];
NSString *dateString = [stringDateFormatter stringFromDate:stringDate];
return dateString;
[stringDateFormatter release];
}
- (void) dealloc
{
[aStage release];
[aMonth release];
[currentElementValue release];
[super dealloc];
}
#end
DAFAppDelegate.h:
#class RootViewController;
#interface DAFAppDelegate : NSObject <UIApplicationDelegate>
{
UIWindow *window;
UINavigationController *navigationController;
IBOutlet UITabBarController *rootTabController;
RootViewController *rootViewController;
NSMutableArray *stages;
}
#property (nonatomic, retain) IBOutlet UIWindow *window;
#property (nonatomic, retain) IBOutlet UITabBarController *rootTabController;
#property (nonatomic, retain) IBOutlet UINavigationController *navigationController;
#property (nonatomic, retain) IBOutlet RootViewController *rootViewController;
#property (nonatomic, retain) NSMutableArray *stages;
+ (void) showAlert;
#end
DAFAppDelegate.m:
#import "DAFAppDelegate.h"
#import "RootViewController.h"
#import "XMLParser.h"
#implementation DAFAppDelegate
#synthesize window;
#synthesize navigationController;
#synthesize rootViewController;
#synthesize rootTabController;
#synthesize stages;
+ (void) showAlert
{
UIAlertView *av = [[[UIAlertView alloc] initWithTitle:#"No Connection" message:#"Could not retrieve data" delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil] autorelease];
[av show];
}
- (void)applicationDidFinishLaunching:(UIApplication *)application
{
NSURL *url = [[NSURL alloc] initWithString:#"http://web.me.com/ijar/Stages.xml"];
NSXMLParser *xmlParser = [[NSXMLParser alloc] initWithContentsOfURL:url];
//Initialize the delegate.
XMLParser *parser = [[XMLParser alloc] initXMLParser];
//Set delegate
[xmlParser setDelegate:parser];
//Start parsing the XML file.
BOOL success = [xmlParser parse];
if(success)
{
NSLog(#"No Errors");
}
else
{
[DAFAppDelegate showAlert];
NSLog(#"Error Error Error!!!");
}
[window addSubview:[rootTabController view]];
[window makeKeyAndVisible];
}
- (void)dealloc
{
[navigationController release];
[rootViewController release];
[rootTabController release];
[window release];
[stages release];
[super dealloc];
}
#end
RootViewController.h:
#class DAFAppDelegate;
#interface RootViewController : UITableViewController
{
DAFAppDelegate *appDelegate;
}
#end
RootViewController.m:
#import "RootViewController.h"
#import "DAFAppDelegate.h"
#import "DetailViewController.h"
#import "XMLParser.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
{
Month *aMonth = [appDelegate.stages objectAtIndex:section];
return aMonth.name;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
Month *aMonth = [appDelegate.stages objectAtIndex:section];
return [aMonth.stagesPerMonth 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;
}
}
}
Month *aMonth = [appDelegate.stages objectAtIndex:indexPath.section];
Stage *aStage = [aMonth.stagesPerMonth objectAtIndex:indexPath.row];
NSString *startDate = [XMLParser stringFromDate:[XMLParser dateFromString:aStage.start]];
NSString *endDate = [XMLParser stringFromDate:[XMLParser dateFromString:aStage.end]];
int endDateLength = endDate.length;
NSString *dateTitle = [NSString stringWithFormat:#"%# - %#", startDate, [endDate substringFromIndex:endDateLength -7]];
cell.titleLabel.text = aStage.title;
cell.dateLabel.text = dateTitle;
cell.nameLabel.text = aStage.teacher;
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];
Month *aMonth = [appDelegate.stages objectAtIndex:indexPath.section];
detailViewController.stage = [aMonth.stagesPerMonth 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
If you want to use the standard activity indicator in the status bar call:
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
Just before you call the parser.
Then once the parser is complete (the didEndDocument method), call:
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
I'm not going to write the code for you, but here are some steps you could take.
1. For a better UX, add the RootViewController.view to the window before you start the xml parsing.
2. In your RootViewController: viewDidLoad method, create and display a UIActivityIndicatorView (a "spinner").
3. When your parsing is done, call a method on the RootViewController that does 3 things:
a) hides the spinner
b) loads the tableView's data source (aMonth.stagesPerMonth)
c) tableView[reloadData];
Good luck.
-Mike
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!!!
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.
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.
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.