Search code examples
iosobjective-cautomatic-ref-countingnsxmlparser

NSXMLParser throwing off EXC_BAD_ACCESS when ARC enabled


iOS beginner here. I'm trying to create an RSS reader for a news website, the RSS parser is in working order but it gives the exception EXC_BAD_ACCESS (code=2 address=0xc) if it's compiled with ARC enabled.

Here's how I call the parser: (in my view controller)

NSMutableArray* articleListMainPage;

- (void)viewDidLoad
{
    NSURL *mainFeed = [[NSURL alloc]initWithString:@"http://my.domain.com/rss.xml"];
    NSXMLParser *nsXmlParser = [[NSXMLParser alloc] initWithContentsOfURL:mainFeed];
    NewsParser *myparser = [[NewsParser alloc] initNewsParser];
    [nsXmlParser setDelegate:myparser];

    if ([nsXmlParser parse]) {
        NSLog(@"Parsed article count : %i", [myparser.articles count]);
        articleListMainPage = [myparser.articles copy];
    } else {
        NSLog(@"Error parsing document!");
    }
    nsXmlParser = nil;
    mainFeed = nil;
    myparser = nil; // This line throws the exception.

    [super viewDidLoad];
}

and here's the parser itself:

// NewsParser.m
#import "NewsParser.h"
#import "RSSEntry.h"

@implementation NewsParser

@synthesize article, articles, currValue;

- (NewsParser *) initNewsParser
{
    if (self = [super init]) return self; else return nil;
}

- (void)parser:(NSXMLParser *)parser
    didStartElement:(NSString *)elementName
    namespaceURI:(NSString *)namespaceURI
    qualifiedName:(NSString *)qualifiedName
    attributes:(NSDictionary *)attributeDict {

    if ([elementName isEqualToString:@"channel"]) {
        self.articles = [[NSMutableArray alloc] init];
    }
    if ([elementName isEqualToString:@"item"]) {
        self.article = [[ArticleEntry alloc] init];
    }
}

- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
    if (!currValue) {
        self.currValue = [[NSMutableString alloc] initWithString:string];
    } else {
        [self.currValue appendString:string];
    }
}

- (void)parser:(NSXMLParser *)parser
    didEndElement:(NSString *)elementName
     namespaceURI:(NSString *)namespaceURI
    qualifiedName:(NSString *)qName {

    if ([elementName isEqualToString:@"channel"]) {
        return;
    }

    if ([elementName isEqualToString:@"item"]) {
        [self.articles addObject:self.article];
        self.article = nil;
    } else {
        if ([[NSArray arrayWithObjects:@"title",@"link",@"description",nil] containsObject:elementName])
             [self.article setValue:self.currValue forKey:elementName];
    }
    self.currValue = nil;
}

@end

//NewsParser.h

#import <Foundation/Foundation.h>
#import "RSSEntry.h"

@interface NewsParser : NSXMLParser <NSXMLParserDelegate> {
    NSMutableString *currValue;
    NSMutableArray *articles;
    ArticleEntry *article;
}
- (NewsParser *) initNewsParser;
@property (nonatomic,retain) ArticleEntry *article;
@property (nonatomic,retain) NSMutableArray *articles;
@property (nonatomic,retain) NSMutableString *currValue;
@end

.. and the class I use for storing the RSS entries.

//RSSEntry.h
#import <Foundation/Foundation.h>

@interface ArticleEntry : NSObject {
    NSString *title;
    NSString *link;
    NSString *description;
}

@property (nonatomic, retain) NSString *title;
@property (nonatomic, retain) NSString *link;
@property (nonatomic, retain) NSString *description;

- (id)initNewArticle:(NSString*)_title url:(NSString*)_link description:(NSString*)_desc;

@end

//RSSEntry.m

#import "RSSEntry.h"

@implementation ArticleEntry
@synthesize title,link,description;
- (id)initNewArticle:(NSString *)_title url:(NSString *)_link description:(NSString *)_desc
{
    if ((self = [super init])) {
        title = [_title copy];
        link = [_link copy];
        description = [_desc copy];
        return self;
    }
    else return nil;
}
@end

Like I said, it works fine without ARC, but I want to know if I'm doing something that I shouldn't be doing (e.g retaining something that I shouldn't or not properly releasing something/overreleasing something) in the code.

Thanks for your time..


Solution

  • So one issue here is that you declared NewsParser to be a subclass of NSXMLParser, which it shouldn't be. It should be a subclass of NSObject (or something else appropriate)

    So in NewsParser.h, try this:

    @interface NewsParser : NSObject <NSXMLParserDelegate>
    

    BTW, you do have memory leaks there without ARC. The analyzer can help you fix those, if you intend to compile this code again without ARC. With or without ARC, there is no garbage collector here (it sounds as if you are counting on one?)