EXC_BAD_ACCESS (code=1, address=0xe0000008) with NSXMLParser


#1

Hi,

I’m trying to write my own XML parsing code using the template from your book with a couple of variations. The most important difference, though I’m not sure it has anything to do with the problem I’m encountering, is that the class I start my parsing with is actually a subclass, and I have to work my way up the hierarchy to get the XML elements I need. Yes, I’m sure I could do something quick and dirty, and just read the elements I want without scaling the hierarchy, but I will have similar obstacles as I progress with this project, so I might as well get over this hump now.

So, here are the interface and implementation for the subclass I start with:

@interface ARC_LOGONRS : ResponseMessage <NSXMLParserDelegate>

@property (nonatomic, weak) id parentParserDelegate;

@end
#import "ARC_LOGONRS.h"

@implementation ARC_LOGONRS
@synthesize parentParserDelegate;

-(id)init
{
    self = [super init];
    
    if (self)
    {
        
    }
    
    return self;
}


-(void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
{
    [super parser:parser didStartElement:elementName namespaceURI:namespaceURI qualifiedName:qName attributes:attributeDict];
    NSLog(@"t%@ found a %@ element", self, elementName);
}

-(void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
    [super parser:parser foundCharacters:string];
    [currentString appendString:string];
}

-(void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
    [super parser:parser didEndElement:elementName namespaceURI:namespaceURI qualifiedName:qName];
    currentString = nil;
    
    if ([elementName isEqual:@"ARC_LOGONRS"])
    {
        [parser setDelegate:parentParserDelegate];
    }
}

@end

Now here are the interface and implementation for the superclass:

#import "MessageObject.h"
#import "Status.h"

@interface ResponseMessage : MessageObject <NSXMLParserDelegate>

@property (nonatomic, weak) id parentParserDelegate;

@property (nonatomic, strong) NSDate *mDTSERVER;
@property (nonatomic, strong) Status *mStatus;

@end
#import "ResponseMessage.h"

@implementation ResponseMessage
@synthesize parentParserDelegate, mStatus, mDTSERVER;

-(id)init
{
    self = [super init];
    
    if (self)
    {
        
    }
    
    return self;
}

-(void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
{
    [super parser:parser didStartElement:elementName namespaceURI:namespaceURI qualifiedName:qName attributes:attributeDict];
    NSLog(@"t%@ found a %@ element", self, elementName);
    
    if([elementName isEqual:@"Status"])
    {
        // When we find a status object, we create an instance of RPMStatus to handle it
        Status *status = [[Status alloc]init];
        
        // Set this object as its parent so it will return control to us
        [status setParentParserDelegate:self];
        
        // Turn the parser loose on it
        [parser setDelegate:status];
    }
}

-(void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
    [super parser:parser foundCharacters:string];
    [currentString appendString:string];
}

-(void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
    [super parser:parser didEndElement:elementName namespaceURI:namespaceURI qualifiedName:qName];
    currentString = nil;
}


@end

I am getting the EXC_BAD_ACCESS error when I my code tries to parse the code property of the Status object I created. Here are the interface and implementation for it:

#import <Foundation/Foundation.h>

@interface Status : NSObject <NSXMLParserDelegate>
{
    NSMutableString *currentString;
}

@property (nonatomic, weak) id parentParserDelegate;

// Not sure what an NSUInteger or Boolean should be, because it can't be 'weak'
@property (nonatomic, assign) NSInteger mCode;
@property (nonatomic, strong) NSMutableArray *mServerErrors;

@end
#import "Status.h"

@implementation Status
@synthesize parentParserDelegate, mCode, mServerErrors;

-(id)init
{
    self = [super init];

    if (self)
    {
    
    }

    return self;
}

-(void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
{
    NSLog(@"t%@ found a %@ element", self, elementName);
    
// ***** MY CODE ALWAYS SEEMS TO DIE SOMEWHERE AROUND HERE *****
    if([elementName isEqual:@"Code"])
    {
        currentString = [[NSMutableString alloc]init];
        //NSNumberFormatter * f = [[NSNumberFormatter alloc] init];
        //[f setNumberStyle:NSNumberFormatterDecimalStyle];
        //NSNumber * myNumber = [f numberFromString:currentString];
        [self setMCode: [currentString integerValue]];
    }
}

-(void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
    [currentString appendString:string];
}

-(void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
    currentString = nil;
    
    if ([elementName isEqual:@"Status"])
    {
        [parser setDelegate:parentParserDelegate];
    }

}

@end

So far, the closest I’ve come to figuring out is some indication that this issue may be related to an ARC bug:
http://stackoverflow.com/questions/13955847/exc-bad-access-with-nsxmlparser-and-arc

I have tried moving the code to parse Code down the hierarchy, but nothing seems to work. I’ve also tried a number of different datatypes for Code: int, NSInteger, NSNumber, etc. I get this bad access error all the time.

So, has anyone encountered this? Can any of you spot a defect in my code or recommend a way around this error, preferably without having to abandon ARC for these classes?

Thank you for your help, and I hope a second sight of eyes can find what I’ve been missing.

Rob


#2

I haven’t tested your code with changes so I’m not sure this will actually fix anything. My understanding of the xml parsing is this:

parser:didStartElement:… This just alerts you that you have found a particular element, “Code”. Here you create an empty string pointer “currentString” and set it appropriately on your item-like object. There is no content yet.

parser:foundCharacters: This reads the content of your “Code” element - puts an actual string into “currentString”

parser:didEndElement: All the content of your element has been read, placed in “currentString” and you have arrived at the closing “\Code” tag.

I think the main problem is that you are doing a [self setMCode: [currentString integerValue]]; in the wrong place. currentString at this point is probably nil. When you need to process the content of an element you should move this code to parser:didEndElement:

Check out the example on page 537 where a date is read from the xml as a string and stored in the item as an NSDate. Your case will be the similar, turning currentString into an NSInteger.

Hope this works for you!