XMLParser Advice - iphone

I'm not sure what I am doing wrong. I have a URL leading to an XML tree that looks like:
<result>
...
<title>
...
</title>
<body>
...
</body>
...
</result>
I just need to parse the file and get the title and body. Here is my object.h:
#import <Foundation/Foundation.h>
#interface Object : NSObject
{
NSString *title;
NSString *description;
}
#property (nonatomic, retain) NSString *title;
#property (nonatomic, retain) NSString *description;
#end
And here is Object.m:
#import "Object.h"
#implementation Object
#synthesize title, description;
-(void) dealloc
{
[title release];
[description release];
[super dealloc];
}
#end
Here is my XMLParser.h:
#import <Foundation/Foundation.h>
#import "Object.h"
#interface XMLParser : NSObject <NSXMLParserDelegate>
{
NSMutableString *currentNodeContent;
NSMutableArray *arrayOfObjects;
NSXMLParser *parser;
Object *currentObject;
}
#property (readonly, retain) NSMutableArray *arrayOfObjects;
-(id) loadXMLbyURL:(NSString *)urlString;
#end
And finally, XMLParser.m:
#import "XMLParser.h"
#import "Object.h"
#implementation XMLParser
#synthesize arrayOfObjects;
-(id) loadXMLbyURL:(NSString *)urlString
{
arrayOfObjects = [[NSMutableArray alloc] init];
NSURL *url = [NSURL URLWithString:urlString];
NSData *data = [[[NSData alloc] initWithContentsOfURL:url] autorelease];
parser = [[NSXMLParser alloc] initWithData:data];
parser.delegate = self;
[parser parse];
return self;
}
-(void) dealloc
{
[parser release];
[super dealloc];
}
-(void) parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
{
if([elementName isEqualToString:#"result"])
{
currentObject = [Object alloc];
}
}
-(void) parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
if([elementName isEqualToString:#"title"])
{
currentObject.title = currentNodeContent;
}
if([elementName isEqualToString:#"body"])
{
currentObject.description = currentNodeContent;
}
if([elementName isEqualToString:#"result"])
{
[arrayOfObjects addObject:currentObject];
[currentObject release];
currentObject = nil;
[currentNodeContent release];
currentNodeContent = nil;
}
}
-(void) parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
currentNodeContent = (NSMutableString *) [string stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
}
#end
In my main code I make a call to XML parser like this:
xmlParser = [[XMLParser alloc] loadXMLbyURL:#"www.websiteWithXML.com"];
However nothing is being placed into my arrayOfObjects (I know this because when I tell a tableview to have as many rows as my array, there are no rows).
please help!!! Thank you in advance!

Not sure if this will help...
Try changing:
arrayOfObjects = [[NSMutableArray alloc] init];
To:
arrayOfObjects = [[NSMutableArray alloc] initWithCapacity:0];
Other than that it appears that your code is fine. Also just because your table isn't loading anything doesn't mean that you do not have objects in your array. Use breakpoints to take a look at your data after you finish parsing and before you try to load your tableview.

Try resetting currentNodeContent inside each of your element starts. For example:
-(void) parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
{
if([elementName isEqualToString:#"result"])
{
currentObject = [Object alloc];
}
else if ([elementName isEqualToString:#"title"] || [elementName isEqualToString:#"body"])
{
[currentNodeContent setString:#""];
}
}
Then, when you receive characters do an append:
-(void) parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
[currentNodeContent appendString:[string stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]];
}
By doing this, you handle the situation where a foundCharacters gets multiple times to capture all of the characters within a given element.

Related

UITableView XML Parser

The data comes smoothly.
But problems have Turkish characters.
Should come as "Düzce" but "ÜZCE" comes.. And,
"Akçakoca" cell in view "çakoca" comes..
XML URL : http://bykrkc.com/test.xml
XMLParser.m;
#import <Foundation/Foundation.h>
#import "XMLParser.h"
#import "XMLFlightList.h"
#implementation XMLParser
#synthesize ucakList = _ucakList;
NSMutableString *currentNodeContent;
NSXMLParser *parser;
XMLFlightList *currentFlight;
bool isStatus;
-(id) loadXMLByUrl:(NSString *)urlString{
_ucakList = [[NSMutableArray alloc] init];
NSError *error;
NSURL *url =[NSURL URLWithString:urlString];
NSString * dataString = [[NSString alloc] initWithContentsOfURL:url encoding:NSUTF8StringEncoding error:&error];
NSData *data = [dataString dataUsingEncoding:NSUTF8StringEncoding allowLossyConversion:YES];
parser =[[NSXMLParser alloc] initWithData:data];
parser.delegate = self;
[parser parse];
return self;
//[NSString stringWithFormat:#"%#",data];
}
-(void) parser:(NSXMLParser *)parser foundCharacters:(NSString *)string{
currentNodeContent = (NSMutableString *)[string stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
}
-(void) parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict{
if([elementName isEqualToString:#"sehirler"])
{
currentFlight = [XMLFlightList alloc];
isStatus = YES;
}
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName{
if(isStatus){
if([elementName isEqualToString:#"ad"]){
currentFlight.name = currentNodeContent;
}
}
if([elementName isEqualToString:#"sehirler"]){
[self.ucakList addObject:currentFlight];
currentFlight =nil;
currentNodeContent = nil;
}
}
#end
XMLParser.h;
#import <Foundation/Foundation.h>
#interface XMLParser : NSObject<NSXMLParserDelegate>
#property (strong,readonly) NSMutableArray *ucakList;
-(id) loadXMLByUrl:(NSString *)urlString;
#end
Result;
2013-12-18 15:49:21.505 tableview01[7663:70b] ÇORUM
2013-12-18 15:49:21.507 tableview01[7663:70b] İSTANBUL
2013-12-18 15:49:21.507 tableview01[7663:70b] ÖMERLİ
2013-12-18 15:49:21.508 tableview01[7663:70b] ÜZCE -> Problem True: DÜZCE
2013-12-18 15:49:21.508 tableview01[7663:70b] çakoca -> Problem True: Akçakoca
2013-12-18 15:49:26.156 tableview01[7663:70b] ÇORUM
Result Images: http://oi42.tinypic.com/2z9mgza.jpg
Your problem in -(void) parser:(NSXMLParser *)parser foundCharacters:(NSString *)string method. This method can be called more then once for each tag.
Try change your code:
-(void) parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
if (currentNodeContent == nil) currentNodeContent = [NSMutableString new];
[currentNodeContent appendString:[string stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]];
}
As alternative you can use XMLConverter for converting your XML to NSDictionary.
This code :
[XMLConverter convertXMLURL:[NSURL URLWithString:#"http://bykrkc.com/test.xml"] completion:^(BOOL success, NSMutableDictionary *dictionary, NSError *error) {
NSArray *elements = dictionary[#"DocumentElement"][#"sehirler"];
for (NSDictionary *dic in elements) {
NSLog(#"%#", dic[#"ad"]);
}
}];
executed with result:
2013-12-18 18:00:46.037 test[690:70b] ÇORUM
2013-12-18 18:00:46.038 test[690:70b] İSTANBUL
2013-12-18 18:00:46.038 test[690:70b] ÖMERLİ
2013-12-18 18:00:46.039 test[690:70b] DÜZCE
2013-12-18 18:00:46.039 test[690:70b] Akçakoca

NSXMLParser divides strings containing foreign(unicode) characters

I have ran into a peculiar problem with NSXMLParser.
For some reason it cuts out all the characters in front of all the norwegian characters æ, ø and å.
However, the problem seems to be the same with all non a-z characters.(All foreign characters)
Examples:
Reality: Mål
Output: ål
Reality: Le chant des sirènes
Output: ènes
Heres an example from the log where I have printed out the string from:
- (void) parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
Log:
2012-02-22 14:00:01.647 VotePlayClient[2776:207] found characters: Le chant des sir
2012-02-22 14:00:01.647 VotePlayClient[2776:207] found characters: ènes
You can clearly see that it jumps to a new line whenever it encounters a foreign letter.
I believe that I have to figure out how to append the string or something to that effect.
Here are the NSXMLParser files:
SearchXMLParser.h
#import <Foundation/Foundation.h>
#import "Search.h"
#interface SearchXMLParser : NSObject <NSXMLParserDelegate>
{
NSMutableString *currentNodeContent;
NSMutableArray *searchhits;
NSMutableArray *trackhits;
NSXMLParser *parser;
Search *currentSearch;
}
#property (readonly, retain) NSMutableArray *searchhits;
#property (readonly, retain) NSMutableArray *trackhits;
-(id) loadXMLByURL:(NSString *)urlString;
#end
SearchXMLParser.m
#import "SearchXMLParser.h"
#import "Search.h"
#implementation SearchXMLParser
#synthesize searchhits, trackhits;
-(id) loadXMLByURL:(NSString *)urlString
{
searchhits = [[NSMutableArray alloc] init];
trackhits = [[NSMutableArray alloc] init];
NSURL *url = [NSURL URLWithString:urlString];
NSData *data = [[NSData alloc] initWithContentsOfURL:url];
parser = [[NSXMLParser alloc] initWithData:data];
parser.delegate = self;
[parser parse];
return self;
}
- (void) parser:(NSXMLParser *)parser didStartElement:(NSString *)elementname namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
{
if ([elementname isEqualToString:#"track"])
{
currentSearch = [Search alloc];
}
if ([elementname isEqualToString:#"track"])
{
currentSearch.trackurl = [attributeDict objectForKey:#"href"];
}
}
- (void) parser:(NSXMLParser *)parser didEndElement:(NSString *)elementname namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
if ([elementname isEqualToString:#"name"])
{
[trackhits addObject:currentNodeContent];
}
if ([elementname isEqualToString:#"track"])
{
currentSearch.track = [trackhits objectAtIndex:0];
currentSearch.artist = [trackhits objectAtIndex:1];
currentSearch.album = [trackhits objectAtIndex:2];
[trackhits removeAllObjects];
[searchhits addObject:currentSearch];
[currentSearch release];
currentSearch = nil;
[currentNodeContent release];
currentNodeContent = nil;
}
}
- (void) parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
NSLog(#"found characters: %#", string);
currentNodeContent = (NSMutableString *) [string stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
}
- (void) dealloc
{
[parser release];
[super dealloc];
}
#end
I have already checked SO for answers and found a couple of similar posts, but nothing that gave a clear solution to this problem.
Can anyone shed some light on this problem? :) Any help is much appreciated!
your parser:foundCharacters: method does not work as it should.
This is from the NSXMLParserDelegate Protocol Reference
The parser object may send the delegate several parser:foundCharacters: messages to report the characters of an element. Because string may be only part of the total character content for the current element, you should append it to the current accumulation of characters until the element changes.
you could try something like this (ARC):
- (void) parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
NSLog(#"found characters: %#", string);
if (!currentNodeContent) {
currentNodeContent = [[NSMutableString alloc] init];
}
[currentNodeContent appendString:string];
}
- (void) parser:(NSXMLParser *)parser didEndElement:(NSString *)elementname namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
// your code here
// when you are done with the string:
currentNodeContent = nil;
}

NSXMLParser Issue

I have an xml file I am parsing.
NSURL *url = [NSURL URLWithString:#"url.xml"];
NSURLRequest *request = [NSURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:60];
self.downloadData = [[NSMutableData alloc] initWithLength:0];
self.connection = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:YES];
I have all the connections working and I thought I had the parsing working but I am having issues and do not know what I am doing wrong.
my didStartElement:
-(void) parser:(NSXMLParser *) parser didStartElement:(NSString *) elementName namespaceURI:(NSString *) namespaceURI qualifiedName:(NSString *) qName attributes:(NSDictionary *) attributeDict {
if ([elementName isEqualToString:kimgurl])
{
elementFound = YES;
}
}
foundCharacter:
-(void)parser:(NSXMLParser *) parser foundCharacters:(NSString *)string {
if (elementFound == YES) {
if(!currentValue)
{
currentValue = [[NSMutableString alloc] init];
}
[currentValue appendString: string];
}
}
then didEndElement:
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
if (elementFound) {
if ([elementName isEqualToString:kimgurl]) {
NSLog(#"imgurl: %#", currentValue);
imageItems.imageURL = currentValue;
NSLog(#"elname: %#", elementName);
NSLog(#"img: %#", kimgurl);
[currentValue setString:#""];
NSLog(#"imageitem: %#", imageItems.imageURL);
}
}
}
I have the NSLogs there because imageItems.imageURL is null. This is a class file that is like this.
ImageItems.h
#interface ImageItems : NSObject {
//parsed data
NSString *imageURL;
}
#property (nonatomic, retain) NSString *imageURL;
#end
ImageItems.m
#import "ImageItems.h"
#implementation ImageItems
#synthesize imageURL;
-(void)dealloc
{
[imageURL release];
[super dealloc];
}
#end
As you can tell by my code I am new to objective-c.
currentValue has the value Im looking for. Why is imageItems null? What am I missing?
I don't see the assignment of "imageItems" anywhere in your code. You probably need to assign it to an instance of ImageItems at some point. Perhaps with self.imageItems = [[[ImageItems alloc] init] autorelease] or imageItems = [[ImageItems alloc] init];?

iPhone XML parser wont add object to mutable array

Greetings,
I have a problem with adding an object from parser to mutable array.
It was working fine until I moved MtableArray from AppDelegate to ViewController. This is where I call parser (MutableArray is inside this View also):
NSURL *url = [[NSURL alloc] initWithString:#"http://example.com"];
NSXMLParser *xmlParser = [[NSXMLParser alloc] initWithContentsOfURL:url];
parser = [[XMLParser alloc] init];
[xmlParser setDelegate:parser];
[xmlParser parse];
...and this is inside parser where objects should be added:
if([elementName isEqualToString:#"Element"]) {
[viewController.marray addObject:parsedObj];
[parsedObj release];
parsedObj = nil;
}
marray is synthesized inside viewController. Parser is doing good job, I tried with NSLog, but marray.count is always (null). Please help!!!
Try like this,
[viewController.marray addObject:[parsedObj copy]];
Have you verified that the marray property is non-nil? If it somehow hasn't been set properly then all of the insertions will be no-ops, and the the result of the count method will be nil.
Now that you've posted more code, this line is your problem:
[marray init];
You need to alloc/init a new NSMutableArray; this line is simply sending the init message to nil.
Can you post more code?
If you are inside view controller when marray is being called, you shouldn't have to call viewController.marray, just marray
One suggestion, from my experience in parsing, is to use an NSMutableDictionary instead of an array..so, for instance:
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
{
currentElement = [elementName copy];
if([elementName isEqualToString:#"item"])
{
//Clear out story item caches
item = [[NSMutableDictionary alloc] init];
currentTitle = [[NSMutableString alloc] init];
currentAddress = [[NSMutableString alloc] init];
currentCity = [[NSMutableString alloc] init];
currentState = [[NSMutableString alloc] init];
currentZip = [[NSMutableString alloc] init];
currentId = [[NSMutableString alloc] init];
}
}
and then to add everything:
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
if([elementName isEqualToString:#"item"])
{
//Save values to an item, then store that item into the array
[item setObject:currentTitle forKey:#"title"];
[item setObject:currentAddress forKey:#"address"];
[item setObject:currentCity forKey:#"city"];
[item setObject:currentState forKey:#"state"];
[item setObject:currentZip forKey:#"zip"];
[item setObject:currentId forKey:#"id"];
// venues is the mutable array
[venues addObject:[item copy]];
} else {
return;
}
}
Now my mutable array has all the elements I need, and I can do various things with it (like reload a table cell). The above code has been tested and verified as working.
Here is some more code:
ViewController.h
#import <UIKit/UIKit.h>
#class XMLParser;
#interface ViewController : UIViewController{
NSMutableArray *marray;
XMLParser *parser;
}
#property (nonatomic, retain) NSMutableArray *marray;
#property (nonatomic, retain) XMLParser *parser;
#end
ViewController.m
#
import "ViewController.h"
#import "ParsedObj.h"
#import "XMLParser.h"
#synthesize marray;
#synthesize parser;
(...)
-(void)search:(id)sender{
[marray init];
NSURL *url = [[NSURL alloc] initWithString:#"http://example.com"];
NSXMLParser *xmlParser = [[NSXMLParser alloc] initWithContentsOfURL:url];
parser = [[XMLParser alloc] init];
[xmlParser setDelegate:parser];
[xmlParser parse];
(...)
#end
XMLparser.h:
#import <UIKit/UIKit.h>
#class ViewController, ParsedObj;
#interface XMLParser : NSObject <NSXMLParserDelegate>{
NSMutableString *currentElementValue;
ViewController *viewController;
ParsedObj *parsedObj;
}
#end
..and XMLparser.m:
#import "XMLParser.h"
#import "ViewController.h"
#import "ParsedObj.h"
#implementation XMLParser
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName
attributes:(NSDictionary *)attributeDict {
if([elementName isEqualToString:#"Root"]) {
//Initialize the array.
viewController.marray = [[NSMutableArray alloc] init];
}
else if([elementName isEqualToString:#"Element"]) {
//Initialize the hotel.
parsedObj = [[ParsedObj alloc] init];
//Extract the attribute here.
parsedObj.ID = [[attributeDict objectForKey:#"id"] integerValue];
}
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
if(!currentElementValue)
currentElementValue = [[NSMutableString alloc] initWithString:string];
else
[currentElementValue appendString:string];
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
if([elementName isEqualToString:#"Root"])
return;
//There is nothing to do if we encounter the Books element here.
//If we encounter the Book element howevere, we want to add the book object to the array
// and release the object.
if([elementName isEqualToString:#"Element"]) {
[accomodationController.marray addObject:parsedObj];
parsedObj = nil;
}
else {
NSString *cValue=[currentElementValue stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
[parsedObj setValue:cValue forKey:elementName];
}
[currentElementValue release];
currentElementValue = nil;
}
- (void)dealloc {
[parsedObj release];
[currentElementValue release];
[super dealloc];
}
#end
I tried a different approach and now I have two solutions and a problem with both of them.
I have a XML parser that should add objects to NSMutableArray from where it has been called at first. Parser is working OK, but here is the problem.
First approach:
I changed NSXMLParser's init method inside my XMLParser.m (mArray is for Mutable Array and):
- (XMLParser *) initXMLParser:(id)sender {
[super init];
mArray=(NSMutableArray *)sender;
return self;}
mArray in implementation file XMLParser.h:
#interface XMLParser : NSObject <NSXMLParserDelegate>{
NSMutableString *currentElementValue;
NSMutableArray *mArray;
Object *aObject;}
-(XMLParser *) initXMLParser:(id)sender;
#end
So, let's get to the part where we call XMLParser from ViewController.m:
mArray = [[NSMutableArray alloc] init];
NSURL *url = [[NSURL alloc] initWithString:#"http://www.a.com/some.xml"];
NSXMLParser *xmlParser = [[NSXMLParser alloc] initWithContentsOfURL:url];
XMLParser *parser = [[XMLParser alloc] initXMLParser:self.mArray];
[xmlParser setDelegate:parser];
[xmlParser parse];
...and here is ViewController.h:
#class XMLParser;
#interface AccomodationSecondViewController : UIViewController{
#public NSMutableArray *mArray;}
#property (nonatomic, retain) NSMutableArray *mArray;
I'm not sure because this is first time I'm using public objects so...
Anyway, this is the part inside XMLParser.m that should add objects:
//This is for closing bracket
if([elementName isEqualToString:#"Element"]) {
[mArray addObject:aObject];
[aObject release];
aObject=nil;}
So, the idea is to make mutable array mArray public inside ViewController and to send pointer to it to XMLParser. I know that this may be little unnatural, but I just want to get it to work.
My other idea is this:
To send pointer of ViewController to XMLParser and do the rest. So, I changed initXMLParser:
- (XMLParser *) initXMLParser:(id)sender {
[super init];
viewController=(ViewController *)sender;
return self;}
and this is the part inside ViewController.m where I call my method:
XMLParser *parser = [[XMLParser alloc] initXMLParser:self];
then I add object:
[viewController.mArray addObject:aObject];
Why is this not working??!!

iPhone: memory leak on autoreleased object?

I am using the XMLParser class, which contains an array with XMLElement objects. The XMLElement is being allocated using the autorelease operation. However, for some reason I'm getting a memory leak (using instruments) on this line:
self.currentElement = [[[XMLElement alloc] init] autorelease];
I'm also releasing the XMLParser object in the caller class. I've highlighted the "problematic" lines in the XMLParser source code below as comment.
I really tried everything to fix it, but unfortunately I do not understand why this is happening at all. Any help is appreciated!
Thank you very much!
// --- XMLElement
#import <Foundation/Foundation.h>
#interface XMLElement : NSObject {
NSDictionary *attributes;
NSMutableArray *children;
NSString *textValue;
NSString *tagName;
XMLElement *parentElement;
}
-(id) init;
-(void) addChild:(XMLElement*) child;
#property(nonatomic, retain) NSDictionary *attributes;
#property(nonatomic, retain) NSMutableArray *children;
#property(nonatomic, retain) NSString *textValue;
#property(nonatomic, retain) NSString *tagName;
#property(nonatomic, retain) XMLElement *parentElement;
#end
#import "XMLElement.h"
#implementation XMLElement
#synthesize attributes, children, textValue, parentElement, tagName;
-(id)init {
if(self = [super init]) {
children = [[NSMutableArray alloc] init];
}
return self;
}
-(void) addChild:(XMLElement*) child{
[self.children addObject:child];
}
- (void)dealloc {
[attributes release];
[children release];
[textValue release];
[tagName release];
[parentElement release];
[super dealloc];
}
#end
// --- XMLParser
#import <Foundation/Foundation.h>
#import "XMLElement.h"
#interface XMLParser : NSObject<NSXMLParserDelegate> {
XMLElement *currentElement;
XMLElement *currentParentElement;
NSMutableString *currentElementValue;
}
- (BOOL)parseData: (NSData*) dataToParse;
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName
attributes:(NSDictionary *)attributeDict;
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string;
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName;
#property (nonatomic, retain) XMLElement *currentParentElement;
#property (nonatomic, retain) XMLElement *currentElement;
#property (nonatomic, retain) NSMutableString *currentElementValue;
#end
#import "XMLParser.h"
#implementation XMLParser
#synthesize currentElementValue, currentElement, currentParentElement;
- (BOOL)parseData: (NSData*) dataToParse {
NSXMLParser *parser = [[NSXMLParser alloc] initWithData:dataToParse];
[parser setDelegate:self];
BOOL success = [parser parse];
[parser release];
return success;
}
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName
attributes:(NSDictionary *)attributeDict{
if(currentElement){
self.currentParentElement = currentElement;
}
// ------------------------------------------------------------
// Instruments is marking this line as source of the leak with 90%
self.currentElement = [[[XMLElement alloc] init] autorelease];
// --------
currentElement.tagName = elementName;
currentElement.attributes = attributeDict;
currentElement.parentElement = self.currentParentElement;
if(self.currentParentElement){
[self.currentParentElement addChild:currentElement]; // and this one with 10%
}
self.currentElementValue = nil;
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string{
if(!currentElement) {
return;
}
if(currentElementValue == nil)
self.currentElementValue = [NSMutableString stringWithString:string];
else
[currentElementValue appendString:string];
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName{
if(currentElement == nil){
if( currentParentElement.parentElement){
self.currentParentElement = currentParentElement.parentElement;
}
}else{
currentElement.textValue = currentElementValue;
[currentElementValue release];
currentElementValue = nil;
self.currentParentElement = currentElement.parentElement;
currentElement = nil;
}
}
- (void)dealloc {
[currentParentElement release];
[currentElement release];
[super dealloc];
}
#end
You must release currentElement in your dealloc method in XMLParser.
It's created as autorelease but then assigned to a retain property, so you are actually retaining it once (which is good).
UPDATE: you should do self.currentElement = nil; when you are done with it, not currentElement = nil;.
This:
self.currentElement = [[[XMLElement alloc] init] autorelease];
retains currentElement (because the property is declared with retain).
Later, in parser:didEndElement:namespaceURI:qualifiedName:, you do this:
currentElement = nil;
which causes the leak because you are not releasing currentElement.
From what I see on this page, this is a documented apple bug. I have experienced the same problem in some of my apps...
Is your XMLParser being run on a background thread? If so, you need to create an NSAutoReleasePool for that thread in order for your [[[XMLElement alloc] init] autorelease] call to work.
HI guys.
the reason is just one simple thing,
instead of
#property(nonatomic, retain) XMLElement *parentElement;
must be
#property(nonatomic, assign) XMLElement *parentElement;
also you need delete [parentElement release] from dealloc
reason is that you are creating cyclic referances. parent to child and chils to parent
and when you are realesing parser object the elements still ocurrs in memory with pointer xount > 0