objective-c之NSXMLParser不解析最后一个节点(可能的内存问题)

mfrbuaa 阅读:51 2025-06-02 22:19:02 评论:0

我有以下.xml文件:

<?xml version="1.0" encoding="UTF-8"?> 
<company> 
    <employee> 
        <id>0</id> 
        <firstname>Jack</firstname> 
        <lastname>Johnson</lastname> 
        <jobtitle>CEO</jobtitle> 
        <departmentid>0</departmentid> 
        <parentid>0</parentid> 
    </employee> 
    <employee> 
        <id>1</id> 
        <firstname>Mik</firstname> 
        <lastname>Black</lastname> 
        <jobtitle>Senior Manager</jobtitle> 
        <departmentid>0</departmentid> 
        <parentid>0</parentid> 
    </employee> 
    <employee> 
        <id>2</id> 
        <firstname>Kim<firstname> 
        <lastname>Friht</lastname> 
        <jobtitle>Senior Manager</jobtitle> 
        <departmentid>0</departmentid> 
        <parentid>0</parentid> 
    </employee> 
... 

以下头文件:
#import <Foundation/Foundation.h> 
#import "Employee.h" 
 
 
@interface IdParser : NSObject <NSXMLParserDelegate> { 
 
    NSXMLParser *xmlParser; 
    NSMutableArray *employees; 
    NSString *currentElement; 
 
    Employee *employee; 
    NSMutableString *tempId, *tempFirstName, *tempLastName, *tempDeptId, *tempJobTitle, *tempParentId; 
 
} 
 
-(NSMutableArray *)getSubordinates:(int)idNumber; 
 
@end 

以及以下实现:
#import "IdParser.h" 
#import "Employee.h" 
 
@implementation IdParser 
 
- (void)start{ 
 
    NSString *file = @"/users/localadmin/Desktop/employeeData.xml"; 
 
    NSFileManager *filemgr = [NSFileManager defaultManager]; 
 
    NSData *dataBuffer = [filemgr contentsAtPath: file]; 
 
    xmlParser = [[NSXMLParser alloc] initWithData:dataBuffer]; 
 
    [xmlParser setDelegate:self];  
 
    [xmlParser parse]; 
 
} 
 
- (void) parser:(NSXMLParser *)parser  
didStartElement:(NSString *)elementName  
   namespaceURI:(NSString *)namespaceURI  
  qualifiedName:(NSString *)qName  
     attributes:(NSDictionary *)attributeDict{ 
 
    [currentElement release]; 
    currentElement = [elementName copy]; 
 
 
    if([elementName isEqualToString:@"employee"]){ 
        employee = [[Employee alloc]init]; 
    } 
    if([elementName isEqualToString:@"id"]){ 
        tempId = [[NSMutableString alloc]init ]; 
    } 
 
    if([elementName isEqualToString:@"firstname"]){ 
        tempFirstName = [[NSMutableString alloc]init ]; 
    } 
 
    if([elementName isEqualToString:@"lastname"]){ 
        tempLastName = [[NSMutableString alloc]init ]; 
    } 
 
    if([elementName isEqualToString:@"jobtitle"]){ 
        tempJobTitle = [[NSMutableString alloc]init ]; 
    } 
 
    if([elementName isEqualToString:@"departmentid"]){ 
        tempDeptId = [[NSMutableString alloc]init ]; 
    } 
 
    if([elementName isEqualToString:@"parentid"]){ 
        tempParentId = [[NSMutableString alloc]init]; 
    } 
 
} 
 
- (void)parser:(NSXMLParser *)parser  
foundCharacters:(NSString *)string{ 
 
    if([currentElement isEqualToString:@"id"]){ 
        [tempId appendString:string];  
    } 
 
    if([currentElement isEqualToString:@"firstname"]){ 
        [tempFirstName appendString:string];  
    } 
 
    if([currentElement isEqualToString:@"lastname"]){ 
        [tempLastName appendString:string];  
    } 
 
    if([currentElement isEqualToString:@"jobtitle"]){ 
        [tempJobTitle appendString:string]; 
 
    } 
 
    if([currentElement isEqualToString:@"departmentid"]){ 
        [tempDeptId appendString:string];  
    } 
 
    if([currentElement isEqualToString:@"parentid"]){ 
        [tempParentId appendString:string];  
    } 
 
} 
 
-(void)parser:(NSXMLParser *)parser  
didEndElement:(NSString *)elementName 
 namespaceURI:(NSString *)namespaceURI 
qualifiedName:(NSString *)qName{ 
 
    if([elementName isEqualToString:@"employee"]){ 
 
        [employee setIdNumber:[tempId intValue]]; 
        [tempId release]; 
 
        [employee setFirstName:tempFirstName]; 
        [tempFirstName release]; 
 
        [employee setLastName:tempLastName]; 
        [tempLastName release]; 
 
        [employee setJobTitle:tempJobTitle]; 
        [tempJobTitle release]; 
 
        [employee setDepartmentIdNumber:[tempDeptId intValue]]; 
        [tempDeptId release]; 
 
        [employee setParentIdNumber:[tempParentId intValue]]; 
        [tempParentId release]; //IF I REMOVE THIS LINE, THE PROGRAM DOES NOT CRASH 
 
        [employees addObject:employee]; 
        [employee release]; 
 
    } 
 
} 
 
@end 

我遇到了一个非常奇怪的问题。当我调用在IdParser中实现的start方法时,它会解析所有内容,但是当它到达XML的最后一个节点(父代)时,会发生一些奇怪的事情。

该程序退出,并且我收到以下错误消息:

malloc: *对象0x4b33360错误:释放的对象的校验和不正确-释放后可能已修改了对象。
*
在malloc_error_break中设置一个断点进行调试
当前语言:自动;目前 objective-c
现在没有可用的内存来编程:不安全地调用malloc

奇怪的是,当我删除 [tempParentId release];行时,程序运行正常。我尝试重新排列XML中的元素,然后再次发生相同的事情:程序在最后一个元素处崩溃。对我而言,这是什么原因,因为我不熟悉Objective-C和iOS,所以我寻求帮助。我猜那里有内存问题,因为删除上面提到的行后程序运行正常。

谢谢你的帮助。

佩塔尔

编辑:

正如我所说的,我是Obj-C的新手,对内存管理以及与之相关的所有事情我不太了解,因此我使用此示例来学习和扩展有关它的知识。就是说,您能在建议如何解决此问题之前,先尝试解释造成该错误的确切原因。

编辑2:

有时,当我运行代码时,程序会冻结,而不是上面描述的错误消息,而在控制台中我只会看到:

当前语言:自动;目前 objective-c
(gdb)

这可能是问题所在的线索,因为我正在经历随机行为。

编辑3:

员工类别:
#import <Foundation/Foundation.h> 
 
 
@interface Employee : NSObject { 
 
    int idNumber; 
    NSString *firstName; 
    NSString *lastName; 
    int departmentIdNumber; 
    NSString *jobTitle; 
    int parentIdNumber; 
} 
 
-(id)initWithIdNumber:(int)idValue 
             firstName:(NSString *)firstNameValue 
             lastName:(NSString *)lastNameValue 
   departmentIdNumber:(int)departmentIdNumberValue 
             jobTitle:(NSString *)jobTitleValue 
       parentIdNumber:(int)parentIdNumberValue; 
 
@property(nonatomic) int idNumber; 
@property(nonatomic, retain) NSString *firstName; 
@property(nonatomic, retain) NSString *lastName; 
@property(nonatomic, retain) NSString *jobTitle; 
@property(nonatomic) int departmentIdNumber; 
@property(nonatomic) int parentIdNumber; 
 
@end 
 
 
#import "Employee.h" 
 
 
@implementation Employee 
 
@synthesize idNumber, firstName, lastName, departmentIdNumber, jobTitle, parentIdNumber; 
 
-(id)initWithIdNumber:(int)idValue 
            firstName:(NSString *)firstNameValue 
             lastName:(NSString *)lastNameValue 
   departmentIdNumber:(int)departmentIdNumberValue 
             jobTitle:(NSString *)jobTitleValue 
       parentIdNumber:(int)parentIdNumberValue{ 
 
    self = [super init]; 
    if(self){ 
        [self setIdNumber:idValue]; 
        [self setFirstName:firstNameValue]; 
        [self setLastName:lastNameValue]; 
        [self setDepartmentIdNumber:departmentIdNumberValue]; 
        [self setJobTitle:jobTitleValue]; 
        [self setParentIdNumber:parentIdNumberValue]; 
    } 
 
    return self; 
 
} 
 
-(NSString *) description{ 
    NSString *desc = [[NSString alloc]initWithFormat:@"ID: %d, firstname: %@, lastname: %@, departmentID: %d, jobtitle: %@, parentID: %d", idNumber, firstName, lastName, departmentIdNumber, jobTitle, parentIdNumber]; 
    return desc; 
} 
 
@end 

请您参考如下方法:

我建议您启用ARC,这将指示编译器为您编写所有内存管理代码。据我所知,它比大多数经验丰富的Objective-C开发人员做得更好,当然也比新开发人员做得更好。

您需要了解有关ARC的所有信息:http://developer.apple.com/library/ios/#releasenotes/ObjectiveC/RN-TransitioningToARC/_index.html

您可以使用Edit -> Refactor -> Convert to Objective-C ARC…为现有项目启用它。这将修改项目中的代码以使其与ARC兼容(因此请确保在执行此操作之前创建备份或提交到源代码控制!)。

当心ARC代码将无法在非常旧的iOS版本上运行。不过不应该是一个问题。


标签:XML
声明

1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。

关注我们

一个IT知识分享的公众号