NSXmlParser и ошибка «изменено после освобождения» - PullRequest
1 голос
/ 07 июля 2011

Как раз тогда, когда я подумал, что освоил управление памятью в 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(@"");
}

После печати «Старт!», «Конец!» и "Чар!" сообщения один раз, так как текст 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 ]

3 голосов
/ 07 июля 2011

Dealloc должен сделать [super dealloc] после освобождения всех переменных экземпляра:

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

, потому что это dealloc в NSObject, что фактически освобождает память, используемую объектом,Когда вы устанавливаете записи в ноль, вы пишете в блок памяти, который уже был освобожден.


Некоторые другие комментарии:

Мне кажется, что вы делаете работу неправильнов -init.Я бы порекомендовал, чтобы у вас был метод (назовите его, скажем, -parse), который фактически вызывает синтаксический анализатор.В данный момент вы выполняете довольно сложные операции над объектом, который не гарантируется для полной инициализации.

Кроме того, лучше не вызывать метод init -initialize:, чтобы избежать путаницы с +initialize, который имеет особое значение в Какао.Я бы назвал это -initWithContent:

Кроме того, переменные вашего экземпляра инициализируются равными нулю до -init, поэтому такие строки, как

ivar = nil;

, бессмысленны в init, и вам также нужноосвободить все переменные вашего экземпляра в dealloc.

1 голос
/ 07 июля 2011

[super dealloc] должен быть вызван в конце. Плюс освободите объекты, которые вы выделяете. Выделенный объект можно освободить, отправив ему сообщение nil, например entries = nil.

ATB.

...