0

I am parsing some XML using TouchXML and I am getting a crash -EXC_BAD_ACCESS. What I found out through trial and error was that if I don't release my CXMLDocument (which I allocate), then everything is fine. Here's my code:

- (NSArray *)getLookUps {

    //Do some stuff and then...

    NSData *tempData = [NSURLConnection sendSynchronousRequest:request 
                                                 returningResponse:nil 
                                                             error:nil];



        CXMLDocument *xmlDoc = [[CXMLDocument alloc] initWithData:tempData options:0 error:nil];
        NSDictionary *mappings = [NSDictionary dictionaryWithObject:@"http://****/****" 
                                                             forKey:@"****"];

        NSLog(@"%@", [[NSString alloc] initWithData:tempData encoding:NSUTF8StringEncoding]);
        NSArray *orders = [[xmlDoc rootElement] nodesForXPath:@"//****:Unit" 
                                            namespaceMappings:mappings 
                                                        error:nil];

        NSMutableArray *units = [NSMutableArray arrayWithCapacity:200];

        for (CXMLElement *order in orders) {
            NSArray *nodes = [order children];
            NSMutableDictionary *dictionary = [NSMutableDictionary dictionaryWithCapacity:[nodes count]];

            for (CXMLElement *node in nodes) {
                [dictionary setObject:[node stringValue] forKey:[node name]];
            }
            [units addObject:dictionary];
        }

        //[xmlDoc release];
    return units;
}

See on the 2nd last line, [xmlDoc release]. I have commented that out, because it crashes if I don't. What am I doing wrong? Thanks.

user635064
  • 6,219
  • 12
  • 54
  • 100
  • At some point you are failing to retain or over-releasing something. Leaking CXMLDocument is just hiding the problem. What do you do with the array returned by this method? Can you show the code that calls this method? – albertamg Jul 17 '11 at 12:10

4 Answers4

1

You probably need to retain your dictionary object otherwise it will also be released when you release the parser. Try changing [units addObject:dictionary]; to [units addObject:[dictionary retain]];.

Another idea is to set your xmlDoc pointer to autorelease:

CXMLDocument *xmlDoc = [[[CXMLDocument alloc] initWithData:tempData options:0 error:nil] autorelease];
Suhail Patel
  • 13,644
  • 2
  • 44
  • 49
  • Thanks for the reply. I changed it to autorelease and its not crashing anymore. But I don't understand why it crashes when I explicitly release it....If something else needs it shouldn't it have retained it? I have alot of other classes which use almost the exact same code and they don't autorelease but they don't crash. Anyways, thanks for your help/ – user635064 Jul 17 '11 at 11:39
  • 1
    I believe `arrayWithCapacity` and `dictionaryWithCapacity` create autoreleased objects so they may be released prematurely when you release the xmlDoc. – Suhail Patel Jul 17 '11 at 11:50
  • Sorry if this is a noob question but what does NSArray or NSDictionary have to do with CXMLDocument? – user635064 Jul 17 '11 at 11:52
  • Well from your question it's not clear if it's actually that line being the exact point of the crash but I assume it crashes when you try to access elements inside the Units Array or the Dictionary inside the Units Array? – Suhail Patel Jul 17 '11 at 11:58
  • No, this is running in an NSOperation and sometime in there, it crashes and XCode takes me to a TouchXML class and point at a line at which its crashing. – user635064 Jul 17 '11 at 12:21
  • I've only played around with the TouchXML library twice but I've used the autorelease method in both instances. It's difficult to explain exactly where it's failing without seeing all your code – Suhail Patel Jul 17 '11 at 12:53
  • SudzC (soap framework) uses TouchXML and I've seen this same behaviour. In my case though, autorelease did not fix it entirely. The crash occurs in CXMLNode's dealloc method. It might be true that releasing the document object before any of its nodes (or whatever) get to be autoreleased will cause the issue, but that shouldn't matter. The objects should be able to be released in any order as long as every participant is keeping their retain counts in check. There is a retention problem there and it might be within TouchXML. – Sebastien Martin Oct 24 '11 at 18:22
  • I am also facing this kind of issues with TouchXML. In My code the following will work "CXMLDocument * __autoreleasing refDocument = [[CXMLDocument alloc] initWithXMLString:refXML options:0 error:&error];" if I am removing "__autoreleasing" it is crashing. Its weird. Not sure why this is happening. – arango_86 Jun 16 '15 at 12:44
1

This bug was reported and is flagged as fixed in the newer versions of the library.

http://code.google.com/p/touchcode/issues/detail?id=35

I haven't tested to see if it is actually fixed, a comment at that URL suggests that it isn't.

In my opinion, this library should be avoided altogether. For iOS apps, use libxml2 for several reasons:

  • It's tested and tried, through and through
  • It's fast and efficient
  • Building a node based representation of your XML might make it easier to code with, but it wastes memory as you always have the entire document in memory. You probably have it more than once while parsing. You should instead design your code to work with the libxml2 approach. You'll agree once you start parsing documents of substantial size.
Sebastien Martin
  • 1,341
  • 11
  • 25
0

I used TouchXML quite often, and (fortunately?) I did not have this problem up to now, but it just happened ...

I posted a solution here: Memory crash using [CXMLNode nodesForXPath] with namespace mappings

Community
  • 1
  • 1
TheEye
  • 9,280
  • 2
  • 42
  • 58
0

I observed in TouchXML Class "CXMLDocument" we have the following handling in "dealloc" method.

- (void)dealloc
{
    // Fix for #35 http://code.google.com/p/touchcode/issues/detail?id=35 -- clear up the node objects first (inside a pool so I _know_ they're cleared) and then freeing the document

    @autoreleasepool {

        nodePool = NULL;

    }
    //
    xmlUnlinkNode(_node);
    xmlFreeDoc((xmlDocPtr)_node);
    _node = NULL;
}

I am not sure why we are using "autoreleasepool" in "dealloc". Is this is standard coding? Correct me if I am wrong.

arango_86
  • 4,236
  • 4
  • 40
  • 46