2011-12-06 10 views
1

私は、次の.xmlファイルを持っている:NSXMLParserは、最後のノード(可能なメモリの問題)を解析しません

<?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 = @"https://stackoverflow.com/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の最後のノード(parentid)に到達すると、何か不思議なことが起こります。

プログラムが終了し、私は次のエラーメッセージが表示されます。

malloc関数:*オブジェクト0x4b33360のエラー:解放されたオブジェクトの不正なチェックサム - オブジェクトはおそらく、解放された後に変更されました。 *は、デバッグするためにmalloc_error_breakにブレークポイントを設定しました 現在の言語:auto;現在、Objective-Cの 今プログラムで使用可能なメモリがありません:私は[tempParentId release];行を削除すると、安全でないが、不思議なことにmalloc

を呼び出すために、プログラムは正常に動作します。私はXMLの要素を再配置しようとしましたが、同じことがもう一度起こります。プログラムは最後の要素でクラッシュします。 Objective-CやiOSの新機能で、何が問題の原因になっているのかは分かりませんので、私は助けを求めています。私は上記の行を削除した後にプログラムが正常に動作するため、どこかにメモリの問題があると思います。

ありがとうございました。

ペタル

EDIT:

私は私がobj-Cに新しいですし、私は学ぶために、この例を使用していますので、私はメモリ管理とそれに接続されたすべての事についてあまり理解していない言ったようにそれについて私の知識を広げてください。それは、あなたがそれを修正する方法を提案する前に説明されたエラーの原因を正確に説明しようとすることができます。

EDIT2:

時々

私が代わりに私が上記のエラーメッセージのコードを、実行すると、プログラムがフリーズし、コンソールに私は以下を参照してください

現在の言語:自動;現在objective-c (gdb)

これは、私がランダムな動作を経験しているため、問題の原因となる可能性があります。

EDIT3:

Employeeクラス:

#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 
+0

あなたのコードはすべてですか?他の場所で 'tempParentId'を使って何もしていないと確信していますか? –

+0

それはすべてのコードです。 tempParentIdはヘッダーファイルで定義され、実装ファイルでアクセスされます。私はそれらを完全にコピーしました。おかげで – Petar

+1

長いショットのビットが、それを解放した直後に 'tempParentId'を' nil'に設定しようとしました。私はあなたのコードでそれがなぜ必要なのかわかりませんが、それは良い習慣と考えられています。 –

答えて

2

私はあなたのためにすべてのメモリ管理コードを書くようにコンパイラに指示しますARCを有効にお勧めします。私が言う限りでは、経験豊富なObjective-C開発者よりも優れており、確かに新しい開発者より優れています。あなたはARCについて知っておく必要があります

すべてがここにある:http://developer.apple.com/library/ios/#releasenotes/ObjectiveC/RN-TransitioningToARC/_index.html

あなたはEdit -> Refactor -> Convert to Objective-C ARC…と既存のプロジェクトのためにそれを有効にすることができます。あなたのプロジェクトのコードをARCと互換性があるように修正します(これを行う前にバックアップを作成するか、ソース管理にコミットしてください!)。

非常に古いバージョンのiOSではARCコードが動作しません。しかし、問題ではありません。

+0

提案していただきありがとうございますが、それは私の問題を解決しません。私がARCを使いたければ、私は決してその質問をしなかったでしょう。私はARCなしでプログラムを書いて助けを求めています。 – Petar

+2

私はそれがほぼ確実にあなたの問題を解決することを知っているので、それを提供するだけです。下位互換性を除いて、ARCをオフにする理由はあまりありません。 –

+0

手動メモリ管理:ARC :: Washboard:洗濯機 –

2

ObjCメモリ管理の最初のルールを破っています。あなたのivarsに直接アクセスしないでください。どこでもアクセサーを使用しますが、deallocinitです。これにより、ほとんどのメモリ管理の問題が解決されます(ブートにはいくつかの問題が解決されます)。上記のコードでは、アクセサを使用した場合にすべて消えてしまうような、扱いにくいメモリ管理がたくさんあります。

@Abhi BeckertさんのARCに関するコメントはいいですし、ARCを使うことができます。 IMO、それは何年もObjCに加えられたもので、誰でもそれを使うべきです。しかし、ARCを使用しても、アクセサを使用してください。

+0

ivarsに直接アクセスするもう一つの理由はパフォーマンスです。これはXMLパーサの有効なポイントになる可能性があります。しかし、コードに直接アクセスする前にコードが必要とする他の多くの最適化があると、どんな利点もあります。 –

+0

非常に高性能なコード(その理由を説明したコメントが付いている)については、これを行うことができます。実際のアドレスを渡す必要があるCおよびC++コードとのインターフェイスでは時折必要です参照により。しかし、あなたが言うように、それは特別なコードのために行うものであり、通常の動作ではありません。 –

+0

@RobNapier:インプリメンテーションファイルでグローバル変数としてインスタンス変数を作成する場合、私はまだメモリ管理のルールを破るつもりですか?変数をグローバル変数にする場合、私のプログラムは動作するはずですか?ありがとう – Petar