Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

tw002

macrumors newbie
Original poster
Feb 23, 2009
16
0
Hi,

I'd consider myself a beginner at iPhone development, but I do have a reasonably solid understanding of how the basics work.

I'm working on an app which reads through an XML file on the internet - the file I'm using for testing purposes: http://www.w3schools.com/xml/note.xml

As it processes the contents of each element, it stores each piece of information (to, from, heading, body) in a separate ivar, and when it reaches the end of the <note> element, it creates an array from these 4 variables, and adds the array to an NSMutableArray (allNotes) which is an instance variable of the class.

-(void) listNoteDetails is called to log the details of the notes:

Code:
-(void) listNoteDetails
{	
	for(NSArray *note in allNotes)	
	{
		NSString *to = [note objectAtIndex:0];
		NSString *from = [note objectAtIndex:1];
		NSString *heading = [note objectAtIndex:2];
		NSString *body = [note objectAtIndex:3];	
             // Code to log details here
	}



}


The problem I'm having is if I call listNoteDetails from the method

Code:
- (void)parserDidEndDocument:(NSXMLParser *)parser
{
[self listNoteDetails]
}


which is implemented in the same class, it all works fine. However I want to be able to log these details by pressing a button. As soon as I change listNoteDetails to an IBAction and connect it to a button, it causes the app to crash when the button is pressed - this occurs whenever something in the listNoteDetails method tries to access the allNotes ivar. Can anyone explain why this happens?

I hope my description of the problem makes some sense.

Thanks.
 
Thanks for your help.


Code:
#import <Foundation/Foundation.h>


@interface XMLController : NSObject < NSXMLParserDelegate >

{

	NSMutableString *currentElement;
	
	NSMutableString *currentTo;
	NSMutableString *currentFrom;
	NSMutableString *currentHeading;
	NSMutableString *currentBody;
	
	NSMutableArray *allNotes;
	
	
}

-(void) listNoteDetails;


@end




Code:
#import "XMLController.h"


@implementation XMLController



-(id)init		// Create parser, set feed, create allNotes array

{

	NSURL *feedURL = [NSURL URLWithString:@"http://www.w3schools.com/xml/note.xml"];
	
	NSXMLParser *parser = [[NSXMLParser alloc] initWithContentsOfURL:feedURL];
	
	allNotes = [NSMutableArray array];
	
	[parser setDelegate:self];
	
	[parser parse];
		
	return self;
	
}


- (void)parserDidStartDocument:(NSXMLParser *)parser
{
	NSLog(@"Started");
	
}


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

	
	currentElement = [NSMutableString stringWithFormat:@"%@", elementName];
	
	
}


// Set ivars to found details, ignoring whitespace
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
	
	
	NSString *trimmedString = [string stringByTrimmingCharactersInSet:
							   [NSCharacterSet whitespaceAndNewlineCharacterSet]];
	
	NSMutableString *finalTrimmed = [NSMutableString stringWithFormat:@"%@", trimmedString];
	
	NSString *nullString = @"";
	
	if ([trimmedString isEqualToString:nullString]) {
		
	} else {
	
		if([currentElement isEqualToString:@"to"])
		{currentTo = finalTrimmed;}
		
		if([currentElement isEqualToString:@"from"])
		{currentFrom = finalTrimmed;}
	
		if([currentElement isEqualToString:@"heading"])
		{currentHeading = finalTrimmed;}
		
		if([currentElement isEqualToString:@"body"])
		{currentBody = finalTrimmed;}
		
	
	}
	
	
}


// If end on note reached, create array of finished note, add to allNotes array

- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName 
												namespaceURI:(NSString *)namespaceURI 
												qualifiedName:(NSString *)qName {
		
	
	NSString *lastTag = @"note";
	
	if ([elementName isEqualToString:lastTag]) {
	
		NSArray *note = [[NSArray alloc] initWithObjects:	
					 currentTo,
					 currentFrom,
					 currentHeading,
					 currentBody,
					 nil];
			
	[allNotes addObject:note];
		
	[note release];
		
	}
	
}





// When finished processing, list all details


- (void)parserDidEndDocument:(NSXMLParser *)parser
{
	[self listNoteDetails];
	
}




-(void) listNoteDetails
{

	
	for(NSArray *note in allNotes)
		
	{
		NSString *to = [note objectAtIndex:0];
		NSString *from = [note objectAtIndex:1];
		NSString *heading = [note objectAtIndex:2];
		NSString *body = [note objectAtIndex:3];
	
		NSString *details = [NSString stringWithFormat:@"To: %@ From: %@ Subject: %@ Note: %@", to, from, heading, body];
	
		NSLog(@"%@", details);
	
	}
	
}




@end
 
Here's your problem, in your init method:

Code:
allNotes = [NSMutableArray array];

[NSMutableArray array] returns an autoreleased object, which means it will be released at some point in the future (when the autorelease pool is drained). By the time you click your button and it tries to access the allNotes variable, it would have been released which is why you get a crash.

You should allocate a non-autoreleased object:

Code:
allNotes = [[NSMutableArray alloc] init];

If you aren't sure about which methods return autoreleased objects, and when to retain/release objects, I recommend reading Apple's Memory Management Guide.
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.