Strange memory behaviour in parser...?

Discussion in 'iOS Programming' started by MACloop, Jan 4, 2010.

  1. MACloop macrumors 6502

    Joined:
    May 18, 2009
    Location:
    Germany
    #1
    Hello all and happy new year to start with!

    I have a question regadring the parsing of an XML file.
    I have an application whicht uses the parsing code below. Everything works all right if I run the code below. The problem is that I have an update function in my app, meaning the user may re-parse the xml file as many times he wants during the program-run. If I release the current-element-variable as in the code below, the app crashes. I use the same parser object as I did the first time and I load the data with NSURLConnection- i.e when the connection is ready is the parser next to do his work.

    Why can I not release the object as I do in my code?
    It must be a huge memory leak if I do not release this object or did I miss something here?

    And, is it all right to release the currentNodeContent variable when the parser is done?

    I hope someone has some good advice? or ideas?
    Thanks in advance,
    MACloop

    Code:
    #pragma mark -
    #pragma mark Parser Delegate Methods
    
    - (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict{
    	currentNodeContent = [[NSMutableString alloc] init];//
    	if([elementName isEqualToString:@"StartTag"]) {//a new item
    		currentElement = [[CurrentElement alloc]init];//allocting 
    	}
    	if([elementName isEqualToString:@"Data"]){
    		nameString = [attributeDict objectForKey:@"name"];
    	} 
    }
    
    - (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName{
    	if([elementName isEqualToString:@"number"]) {
    		[currentElement setValue:currentNodeContent forKey:@"number"];
    	}
    	if([elementName isEqualToString:@"description"]) {
    		[currentElement setValue:currentNodeContent forKey:@"description"];
    	}
    	
    	if([elementName isEqualToString:@"Data"]) {
    		if([nameString isEqualToString:@"street"]) {
    			[currentElement setValue:currentNodeContent forKey:@"street"];
    		}
    		if([nameString isEqualToString:@"town"]){
    			[currentElement setValue:currentNodeContent forKey:@"town"];
    		}
    		if([nameString isEqualToString:@"mail"]){
    			[currentElement setValue:currentNodeContent forKey:@"mail"];
    		}
    	}
    	if([elementName isEqualToString:@"StartTag"]) {
    		[arrayWithAllObjects addObject:currentElement];
    		[currentElement release];
    	}
    	
    	else
    		return;
    }
    
    - (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string{
    	[currentNodeContent appendString:[string stringByTrimmingCharactersInSet:[NSCharacterSet newlineCharacterSet]]];
    }
    
    - (void)parserDidEndDocument:(NSXMLParser *)parser {
    	[currentNodeContent release];
    	
    //doing the rest here...
    
    }
    
    - (void)parser:(NSXMLParser *)p parseErrorOccurred:(NSError *)parseError {
    	[p abortParsing];
    	parserProblems = TRUE;
    	UIAlertView *alert = [[[UIAlertView alloc]initWithTitle:@"Error" message:@"Problems" delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil]autorelease];
    	[alert show];
    }
    
     
  2. MACloop thread starter macrumors 6502

    Joined:
    May 18, 2009
    Location:
    Germany
    #2
    I think I found a solution. I do not know if it is optimal, but it seem to work and does not look to bad when running the app in "leaks". I did following(new things maked red):

    Code:
    #pragma mark -
    #pragma mark Parser Delegate Methods
    
    - (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict{
    	currentNodeContent = [[NSMutableString alloc] init];//
    	if([elementName isEqualToString:@"StartTag"]) {//a new item
    		currentElement = [[CurrentElement alloc]init];//allocting 
    	}
    	if([elementName isEqualToString:@"Data"]){
    		nameString = [attributeDict objectForKey:@"name"];
    	} 
    }
    
    - (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName{
    	if([elementName isEqualToString:@"number"]) {
    		[currentElement setValue:currentNodeContent forKey:@"number"];
    [COLOR="Red"][currentNodeContent release];
    		currentNodeContent = nil;[/COLOR]
    	}
    	if([elementName isEqualToString:@"description"]) {
    		[currentElement setValue:currentNodeContent forKey:@"description"];
    [COLOR="Red"][currentNodeContent release];
    		currentNodeContent = nil;[/COLOR]
    	}
    	
    	if([elementName isEqualToString:@"Data"]) {
    		if([nameString isEqualToString:@"street"]) {
    			[currentElement setValue:currentNodeContent forKey:@"street"];
    [COLOR="Red"][currentNodeContent release];
    		currentNodeContent = nil;[/COLOR]
    		}
    		if([nameString isEqualToString:@"town"]){
    			[currentElement setValue:currentNodeContent forKey:@"town"];
    [COLOR="Red"][currentNodeContent release];
    		currentNodeContent = nil;[/COLOR]
    		}
    		if([nameString isEqualToString:@"mail"]){
    			[currentElement setValue:currentNodeContent forKey:@"mail"];
    [COLOR="Red"][currentNodeContent release];
    		currentNodeContent = nil;[/COLOR]
    		}
    	}
    	if([elementName isEqualToString:@"StartTag"]) {
    		[arrayWithAllObjects addObject:currentElement];
    		[currentElement release];
    [COLOR="Red"][currentElement release];[/COLOR]
    	}
    	
    	else
    		return;
    }
    
    - (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string{
    	[currentNodeContent appendString:[string stringByTrimmingCharactersInSet:[NSCharacterSet newlineCharacterSet]]];
    }
    
    - (void)parserDidEndDocument:(NSXMLParser *)parser {
    	
    //doing the rest here...
    
    }
    
    - (void)parser:(NSXMLParser *)p parseErrorOccurred:(NSError *)parseError {
    	[p abortParsing];
    	parserProblems = TRUE;
    	UIAlertView *alert = [[[UIAlertView alloc]initWithTitle:@"Error" message:@"Problems" delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil]autorelease];
    	[alert show];
    }
    
    
    So how does this solution look? Is it the way to solve this problem? And why do you have to write currentElement = nil after the release?

    Another parsing question is the one when a parser fails. I have used the delegate method above - is that corrent? I have tried to provoke a failure in order to get this method called as I let the parser read data from a wrong formed document. By wrong formed I mean a document with other tags than the one the parser is looking for. But that did not lead to the method being called - why?

    Thanks in advance
    MACloop
     

Share This Page