Problem with NSXMLParser and NSMutableArray

Discussion in 'iOS Programming' started by MACloop, Jun 22, 2009.

  1. MACloop macrumors 6502

    Joined:
    May 18, 2009
    Location:
    Germany
    #1
    Hello everybody,
    I have tried some days now to write an app where I use the NSXMLParser. I have an URL and I am able to read from the source (it is an kml-file) and print the result using NSLog. I have tried to filter the items to be printed on the screen and that works fine as well. My problem is, that no matter how I try, the NSMutableArray I use to store the data is remaining empty. To make it a bit easier to understand my problem- here is some code:
    The class creating an object car:

    @implementation Car
    @synthesize name;
    @synthesize description;
    @synthesize coordinates;
    @synthesize point;

    - (void) dealloc {
    [description release];
    [coordinates release];
    [name release];
    [point release];
    [super dealloc];
    }

    @end


    In the class XMLParser.m is the parser and the mutableArray defined:
    #import "XMLParser.h"
    #import "Car2GoAppDelegate.h"
    #import "Car.h"

    @implementation XMLParser
    @synthesize theTestArrray;
    @synthesize appDelegate;
    @synthesize currentElementValue;
    @synthesize aCar;

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

    - (void) parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName attribute:(NSDictionary *)attributeDict {
    if([elementName isEqualToString:mad:"kml"]) {
    appDelegate.cars = [[[NSMutableArray alloc]init]retain];
    }
    else if([elementName isEqualToString:mad:"Placemark"]) {

    aCar = [[Car alloc]init];
    }
    else
    return;
    NSLog(@"In the didStartElement method: %@", elementName);
    }

    - (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:mad:"kml"])
    return;
    if([elementName isEqualToString:mad:"Style"])
    return;
    if([elementName isEqualToString:mad:"IconStyle"])
    return;
    if([elementName isEqualToString:mad:"Icon"])
    return;
    if([elementName isEqualToString:mad:"color"])
    return;
    if([elementName isEqualToString:mad:"colorMode"])
    return;
    if([elementName isEqualToString:mad:"scale"])
    return;
    if([elementName isEqualToString:mad:"href"])
    return;
    if([elementName isEqualToString:mad:"styleUrl"])
    return;
    if([elementName isEqualToString:mad:"a"])
    return;

    if([elementName isEqualToString:mad:"Placemark"]) {
    [appDelegate.cars addObject:aCar];
    [aCar release];
    aCar = nil;
    }

    else {
    [aCar setValue:currentElementValue forKey:elementName];
    }
    [currentElementValue release];
    currentElementValue = nil;
    }

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

    @end


    The delegate for the whole app. I am using a rootviewcontroller containing and handling a flipsideview.

    @implementation Car2GoAppDelegate

    @synthesize window;
    @synthesize rootViewController;
    @synthesize cars;
    @synthesize thisCar;

    - (void)applicationDidFinishLaunching:(UIApplication *)application {

    NSString *URLToKml = [NSString stringWithFormat:mad:"%@", @"http:/d9t.de/nearest/kml"];
    NSURL *url = [NSURL URLWithString:URLToKml];
    NSXMLParser *xmlParser = [[NSXMLParser alloc]initWithContentsOfURL:url];
    XMLParser *parser = [[XMLParser alloc]initXMLParser];
    [xmlParser setDelegate:parser];

    BOOL success = [xmlParser parse];
    if(success) {
    NSLog(@"No errors");
    NSInteger *test = [cars count];
    NSLog(@"The number of elements in the array:%i", test);
    }
    else
    NSLog(@"Error by parsing");

    [window addSubview:[rootViewController view]];
    [window makeKeyAndVisible];
    }

    - (void)dealloc {
    [cars release];
    [rootViewController release];
    [window release];
    [super dealloc];
    }




    I can compile the program without problems and I get the control output "No errors" indicating that the parsing is ok (see above). But I do not understand why the array cars with the data always remains empty??? Can anyone help me with this problem? I have followed the tutorial here to create my app...

    Thanks in advance!
    loop
     
  2. robbieduncan Moderator emeritus

    robbieduncan

    Joined:
    Jul 24, 2002
    Location:
    London
    #2
    Please use the magic code tags ([ code ]my code here[ /code ] without the spaces in the tags)...
     
  3. namanhams macrumors regular

    Joined:
    Jun 3, 2009
    #3
    My idea : i just read through the code i dont think it's hard to debug your code by using NSLog. Printing out wherever you add a car to your array may help.
     
  4. MACloop thread starter macrumors 6502

    Joined:
    May 18, 2009
    Location:
    Germany
    #4
    Hello and thanks for your answers!
    @robbieduncan: I am not sure I understand what you mean? Do you mean in the kml/xml file? If so - I do not have any influence on how it is created - I only read it. If you mena something in my code...could you give me an example on what I could change in the code? I am quite new to object-c making me abit confused about the syntax :-S

    @namanhams: I have used NSLog to follow the flow in my code and it did indeed give me some hints. The problem is only that I can write the objects from the kml file out oin screen using NSLog. Only the array remains empty... I dont understand why??
    I have retein the array and I have allocated it to. I have initiated it and everytime I reach a <Placemark> end tag I put the object car into the array. From the array I then read the object's parts like for instance:
    Car *theFirstCar = [cars objectAtIndex:0];
    NSLog(@"The first car's coordinates stored in the array:%@", theFirst.coordinates);


    By writing the following code I intended to count the number of elements in the cars array, and the NSLog alway shows a count of 0...?:
    NSInteger *test = [cars count];
    NSLog(@"The number of elements in the array:%i", test);


    So, I have no Idea why my array is not populated? Where in the code should I add objects to it? Am I thinking wrong about how tosave the objects? Am I missing some detail by creating the array or by creating the car objects. I have tested to print out a car object as well and did not get that to work eather:
    (in the xmlParser.m)
    else {
    [aCar setValue:currentElementValue forKey:elementName];
    NSLog(@"The description of the current car:%@",aCar.description);
    }


    Does anyone have any experience with xmlParser and any hint to help me solve this? I am sure that it is not very hard, because the parsing itself works fine and I can print out the items from the xml file without problems...

    Thanks in advance!
    /loop
     
  5. robbieduncan Moderator emeritus

    robbieduncan

    Joined:
    Jul 24, 2002
    Location:
    London
    #5
    No I mean posting code onto this website: it formats the code making it readable and turns of generation of :) characters.

    Like this:

    Code:
    -(void) myMethod:(NSString *) myParam
    {
    }
    
     
  6. MACloop thread starter macrumors 6502

    Joined:
    May 18, 2009
    Location:
    Germany
    #6
    Ah, ok! Here comes the code in a more readable format:
    Code:
    @implementation Car
    @synthesize name;
    @synthesize description;
    @synthesize coordinates;
    @synthesize point;
    
    - (void) dealloc {
    [description release];
    [coordinates release];
    [name release];
    [point release];
    [super dealloc];
    }
    
    @end
    
    In the class XMLParser.m is the parser and the mutableArray defined:
    Code:
    #import "XMLParser.h"
    #import "Car2GoAppDelegate.h"
    #import "Car.h"
    
    @implementation XMLParser
    @synthesize theTestArrray;
    @synthesize appDelegate;
    @synthesize currentElementValue;
    @synthesize aCar;
    
    - (XMLParser *) initXMLParser {
    [super init];
    appDelegate = (Car2GoAppDelegate *) [[UIApplication sharedApplication]delegate];
    return self;
    }
    
    - (void) parserNSXMLParser *)parser didStartElementNSString *)elementName namespaceURINSString *)namespaceURI qualifiedNameNSString *)qualifiedName attributeNSDictionary *)attributeDict {
    if([elementName isEqualToString:@"kml"]) {
    appDelegate.cars = [[[NSMutableArray alloc]init]retain];
    }
    else if([elementName isEqualToString:@"Placemark"]) {
    
    aCar = [[Car alloc]init];
    }
    else
    return;
    NSLog(@"In the didStartElement method: %@", elementName);
    }
    
    - (void)parserNSXMLParser *)parser foundCharactersNSString *) string {
    if(!currentElementValue) {
    currentElementValue = [[NSMutableString alloc]initWithString:string];
    }
    else {
    [currentElementValue appendString:string];
    }
    }
    
    - (void) parserNSXMLParser *)parser didEndElementNSString *) elementName namespaceURINSString *)namespaceURI qualifiedNameNSString *)qName {
    if([elementName isEqualToString:@"kml"])
    return;
    if([elementName isEqualToString:@"Style"])
    return;
    if([elementName isEqualToString:@"IconStyle"])
    return;
    if([elementName isEqualToString:@"Icon"])
    return;
    if([elementName isEqualToString:@"color"])
    return;
    if([elementName isEqualToString:@"colorMode"])
    return;
    if([elementName isEqualToString:@"scale"])
    return;
    if([elementName isEqualToString:@"href"])
    return;
    if([elementName isEqualToString:@"styleUrl"])
    return;
    if([elementName isEqualToString:@"a"])
    return;
    
    if([elementName isEqualToString:@"Placemark"]) {
    [appDelegate.cars addObject:aCar];
    [aCar release];
    aCar = nil;
    }
    
    else {
    [aCar setValue:currentElementValue forKey:elementName];
    }
    [currentElementValue release];
    currentElementValue = nil;
    }
    
    - (void) dealloc {
    [aCar release];
    [currentElementValue release];
    [super dealloc];
    }
    
    @end
    
    The delegate for the whole app. I am using a rootviewcontroller containing and handling a flipsideview.
    Code:
    @implementation Car2GoAppDelegate
    
    @synthesize window;
    @synthesize rootViewController;
    @synthesize cars;
    @synthesize thisCar;
    
    - (void)applicationDidFinishLaunchingUIApplication *)application {
    
    NSString *URLToKml = [NSString stringWithFormat:@"%@", @"http:/d9t.de/nearest/kml"];
    NSURL *url = [NSURL URLWithString:URLToKml];
    NSXMLParser *xmlParser = [[NSXMLParser alloc]initWithContentsOfURL:url];
    XMLParser *parser = [[XMLParser alloc]initXMLParser];
    [xmlParser setDelegatearser];
    
    BOOL success = [xmlParser parse];
    if(success) {
    NSLog(@"No errors");
    NSInteger *test = [cars count];
    NSLog(@"The number of elements in the array:%i", test);
    }
    else
    NSLog(@"Error by parsing");
    
    [window addSubview:[rootViewController view]];
    [window makeKeyAndVisible];
    }
    
    - (void)dealloc {
    [cars release];
    [rootViewController release];
    [window release];
    [super dealloc];
    }
    Another question:
    How does
    Code:
    [aCar setValue:currentElementValue forKey:elementName];
    work?
    I thought that I might have defined the key false and because of that does not the car object contain any data?

    Another issue is, in the tutorial code was a part like:
    Code:
    //Extract the attribute here.
    aBook.bookID = [[attributeDict objectForKey:@"id"] integerValue];
    
    Because I do not have anything like an id or any attributes at all in the tags, i cannot define this part, can I?
    Or shall I define it in an alternative way?
    What is actually this attributeDict?

    Thanks in advance!
    /loop
     
  7. MACloop thread starter macrumors 6502

    Joined:
    May 18, 2009
    Location:
    Germany
    #7
    Hi again!
    I suppose that at least one of my problems is in the following code:

    Code:
    	
    else if([elementName isEqualToString:@"description"]) {
    [aCar setValue:currentElementValue forKey:elementName];
    NSLog(@"aCars description is:%@", aCar.description);
    This is in the didEndElement method and my intention is to go to the element tagged with description and that part seems to work fine. After finding such a element I intend to take the value found and save it into the part of a Car object called description (it is a NSString). The last code row should, but DOES NOT, print out the value I assigned to the car object... it is always null.... no matter how I try...why?

    Thanks in advance!
    /loop
     
  8. namanhams macrumors regular

    Joined:
    Jun 3, 2009
    #8
    Hi MACloop,

    In the XMLParser file, i think the bug is in the second method (... didStartElement...). May be the mutable array (cars) is not created yet, so it's still nill, or may be the car is not created yet. In objective C, message to nill object is allowed.
    Hope this helps.
     
  9. namanhams macrumors regular

    Joined:
    Jun 3, 2009
    #9
    Sorry i haven't read your code yet, but since i just had the same problem minutes ago, and i found that it's because of the nill object, so i guess yours may be same.
     
  10. MACloop thread starter macrumors 6502

    Joined:
    May 18, 2009
    Location:
    Germany
    #10
    Thanks for your answer namanhams!
    I am not sure I understand what you mean :eek: ...
    I am creating an array to fill with objects if the parser read the tag <kml>. This tag only appears at the beginning of the file, indicating that we are beginning to read a new file. The car object is created when the tag <Placemark> is read, because a placemark includes all the data to be stored into the car object... This is how I reason...but it might of course be wrong...
    What do you mean about the nil values? When I print the value out in the console using NSLog the value shown on the screen is (null)... hmmm... :confused:


    /loop
     
  11. namanhams macrumors regular

    Joined:
    Jun 3, 2009
    #11
    Yes i meant "null" (i think null and nill are the same :cool:)

    NSMutableArray *cars; // now car is still null
    cars = [[NSMutableArray alloc] init]; // car is created, not null anymore.

    For the method that i stated above, i see that only 1 of "cars" or "aCar" is created because they are put into if-else. That means, 1 of them is null.
    That's the problem.
     
  12. MACloop thread starter macrumors 6502

    Joined:
    May 18, 2009
    Location:
    Germany
    #12
    Thanks again!
    Yes nil and null are the same...I thought so too
    I have initialized the array as you write above and after that I add objects to it...I do not understand why the array remains empty...? I think it would be helpful if you could perhapt give me an example...using my code...? Thanks in advance!
    /loop
     
  13. namanhams macrumors regular

    Joined:
    Jun 3, 2009
    #13

    In which part do you initialize the array ?
     
  14. MACloop thread starter macrumors 6502

    Joined:
    May 18, 2009
    Location:
    Germany
    #14
    I initialize the array when the parser encounters a <kml> tag in the following code:

    Code:
    - (void) parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName attribute:(NSDictionary *)attributeDict {	
    	if([elementName isEqualToString:@"kml"]) {
    		appDelegate.cars = [[NSMutableArray alloc]init];//a new file to read - an new array is created
    	}
    	else if([elementName isEqualToString:@"Placemark"]) {
    		aCar = [[Car alloc]init];//initialize a new car object when a Placemark tag was found
    	}
    
     
  15. Vinprakash macrumors newbie

    Joined:
    Mar 13, 2009
  16. MACloop thread starter macrumors 6502

    Joined:
    May 18, 2009
    Location:
    Germany
    #16
    The code for the class have I posted here above, but here it comes again:
    Code:
    @implementation Car
    @synthesize name;
    @synthesize description;
    @synthesize coordinates;
    @synthesize point;
    
    - (void) dealloc {
    [description release];
    [coordinates release];
    [name release];
    [point release];
    [super dealloc];
    }
    
    @end
    
    Perhapt something is wrong with the object Car and the definition of it?
    /loop
     
  17. MACloop thread starter macrumors 6502

    Joined:
    May 18, 2009
    Location:
    Germany
    #17
    The tutorial I followed used the appDelegate.cars to point at the array? Is there something wrong with that? But if it was, the car object should hold some data anyway....hmmm :confused:
     
  18. namanhams macrumors regular

    Joined:
    Jun 3, 2009
    #18
    Code:
    - (void) parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName attribute:(NSDictionary *)attributeDict {	
    	if([elementName isEqualToString:@"kml"]) {
    		appDelegate.cars = [[NSMutableArray alloc]init];//a new file to read - an new array is created
    	}
    	else if([elementName isEqualToString:@"Placemark"]) {
    		aCar = [[Car alloc]init];//initialize a new car object when a Placemark tag was found
    	}
    
    Hi,

    Do you try to print out the number of elements in "cars" everytime you insert a car ?
     
  19. dejo Moderator

    dejo

    Staff Member

    Joined:
    Sep 2, 2004
    Location:
    The Centennial State
    #19
    MACloop, can we see the interface (.h) file for your Car class? You seem to be trying to use it like an NSDictionary (as in, "[aCar setValue:currentElementValue forKey:elementName];") but I doubt that is how it is defined.

    Also, nil and NULL are not the same thing and not interchangeable. nil is specific to Objective-C and has more powers than NULL.

    Are you sure you have a good handle on the basics of Objective-C? Perhaps it is time to step back from the real coding and review those first before continuing.
     

Share This Page