NSXmlParser和“被释放后修改”错误

时间:2011-07-07 07:43:47

标签: iphone objective-c memory-management nsxmlparser

当我以为我已经掌握了Objective-C的内存管理时,这个错误让我无处可逃......

请考虑以下代码:

@implementation JglpNewsEntryParser


- (JglpNewsEntryParser *) initialize : (NSString *)content {
    self = [super init];
    if (self) {
        currentHeader = nil;
        currentText = nil;
        currentDate = nil;
        currentFullArticleUrl = nil;
        entries = [[NSMutableArray alloc] init];
        NSData *data = [content dataUsingEncoding: [NSString defaultCStringEncoding]];
        NSXMLParser *parser = [[[NSXMLParser alloc] initWithData:data] autorelease];
        [parser setDelegate: self];
        [parser parse];
    }
    return self;
}

- (void)parser: (NSXMLParser *)parser didStartElement: (NSString *)elementName namespaceURI: (NSString *)namespaceURI qualifiedName: (NSString *)qName attributes: (NSDictionary *)attributeDict {
    NSLog(@"Start!");
}

- (void)parser: (NSXMLParser *)parser didEndElement: (NSString *)elementName namespaceURI: (NSString *)namespaceURI qualifiedName: (NSString *)qName {
    NSLog(@"End!");
}

- (void)parser: (NSXMLParser *)parser foundCharacters: (NSString *)content {
    NSLog(@"Char!");
}

- (void)dealloc {
    [super dealloc];
    [entries release];
    entries = nil;
}

该类用于我的单元测试,方法如下:

- (void) testConstruct {
    NSString *path = [[NSBundle bundleForClass:JglpNewsEntryParserTest.class] pathForResource: @"single-news-entry" ofType: @"html"];
    NSError *error = nil;
    NSString *data = [NSString stringWithContentsOfFile: path encoding: NSUTF8StringEncoding error: &error];
    JglpNewsEntryParser *parser = [[[JglpNewsEntryParser alloc] initialize: data] autorelease];
    STFail(@"");
}

打印“开始!”,“结束!”和“Char!”消息一次,因为文本XML只包含一个条目,测试失败,因为它应该在STFail。但是,之后我收到以下内存错误消息:

malloc: *** error for object 0xedf434: incorrect checksum for freed object - object was probably modified after being freed.
*** set a breakpoint in malloc_error_break to debug

data中构建initialize对象似乎引发了世界末日机器。如果我取消注释,消息就会消失。

        // ...
        /*NSData *data = [content dataUsingEncoding: [NSString defaultCStringEncoding]];
        NSXMLParser *parser = [[[NSXMLParser alloc] initWithData:data] autorelease];
        [parser setDelegate: self];
        [parser parse];*/
    }
    return self;
}

NSData构建NSString对象时,我是否遗漏了某些内容?

感谢您的任何建议和问候 KC

2 个答案:

答案 0 :(得分:3)

在发布所有实例变量后,Dealloc应该[super dealloc]

- (void)dealloc {
    [entries release];
    entries = nil;
    [super dealloc];
}

因为dealloc中的NSObject实际上释放了对象使用的内存。当您将条目设置为nil时,您正在写入已经释放的内存块。


其他一些评论:

我在-init开展工作似乎不对。我建议你有一个实际调用解析器的方法(称之为,例如,-parse)。目前,您正在对一个无法完全初始化的对象执行相当复杂的操作。

此外,最好不要调用init方法-initialize:以避免与在Cocoa中具有特定含义的+initialize混淆。我称之为-initWithContent:

此外,您的实例变量在-init之前初始化为nil,所以像

这样的行
ivar = nil;
<{1>}中的

毫无意义,您还需要在init中释放所有您的实例变量。

答案 1 :(得分:1)

最后应调用[super dealloc]。再发布您分配的对象。可以通过向entries = nil发送消息nil来释放已分配的对象。

ATB。