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

标签 objective-c ios nsxmlparser

我有以下.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版本上运行。不过不应该是一个问题。

关于objective-c - NSXMLParser不解析最后一个节点(可能的内存问题),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8405532/

相关文章:

iphone - iOS 编程中的内存管理

ios - 此处无法针对 armv7 进行编译,有效架构为 armv6、armv7 和 i386

ios - 使用 Healthkit 获取和设置医疗 ID 中的信息?

ios - 使用 NSXMLParser 仅在特定标记内解析元素

ios - 字典和副本的 NSArray

objective-c - 处理ARC中的指针对指针所有权问题

ios - GPUImage 平均颜色与应用的灰度过滤器不匹配

ios - 将两个具有相同 UUID 的 BLE 设备配对(使用 CoreBluetooth)

ios - didEndDragging 后取消 UIScrollView 弹跳动画?

objective-c - 将核心数据信息转换为 XML,反之亦然