2009-08-11 6 views
3
내가 파일로 내 자신의 만든 클래스를 저장해야

, 나는 좋은 방법은 내 클래스 정의는 다음과 같습니다 NSKeyedArchiver와 NSKeyedUnarchiver 를 사용하는 것으로, 인터넷에서 발견 구현 방법 initWithCoder:encodeWithCoder:이 방법 :아이폰 직렬화 문제

:

- (id)initWithCoder:(NSCoder *)coder 
    { 
     if([coder allowsKeyedCoding]) 
     { 
      strCompleteWord = [[coder decodeObjectForKey:@"CompletedWord"] copy]; 
      strWordToGuess = [[coder decodeObjectForKey:@"WordToGuess"] copy]; 
      arGuessedLetters = [[coder decodeObjectForKey:@"GuessedLetters"] retain]; 
     // arGuessedLettersPos = [[coder decodeObjectForKey:@"GuessedLettersPos"] retain]; 
      iScore = [coder decodeIntegerForKey:@"Score"]; 
      iLives = [coder decodeIntegerForKey:@"Lives"]; 
      iRocksFallen = [coder decodeIntegerForKey:@"RocksFallen"]; 
      bGameCompleted = [coder decodeBoolForKey:@"GameCompleted"]; 
      bGameOver = [coder decodeBoolForKey:@"GameOver"]; 
     } 
     else 
     { 
      strCompleteWord = [[coder decodeObject] retain]; 
      strWordToGuess = [[coder decodeObject] retain]; 
      arGuessedLetters = [[coder decodeObject] retain]; 
     // arGuessedLettersPos = [[coder decodeObject] retain]; 
      [coder decodeValueOfObjCType:@encode(NSInteger) at:&iScore]; 
      [coder decodeValueOfObjCType:@encode(NSInteger) at:&iLives]; 
      [coder decodeValueOfObjCType:@encode(NSInteger) at:&iRocksFallen]; 
      [coder decodeValueOfObjCType:@encode(BOOL) at:&bGameCompleted]; 
      [coder decodeValueOfObjCType:@encode(BOOL) at:&bGameOver]; 
     } 

     return self; 
    } 

    - (void)encodeWithCoder:(NSCoder *)coder 
    { 
     if([coder allowsKeyedCoding]) 
     { 
      [coder encodeObject:strCompleteWord forKey:@"CompleteWord"]; 
      [coder encodeObject:strWordToGuess forKey:@"WordToGuess"]; 
      [coder encodeObject:arGuessedLetters forKey:@"GuessedLetters"]; 
      //[coder encodeObject:arGuessedLettersPos forKey:@"GuessedLettersPos"]; 
      [coder encodeInteger:iScore forKey:@"Score"]; 
      [coder encodeInteger:iLives forKey:@"Lives"]; 
      [coder encodeInteger:iRocksFallen forKey:@"RocksFallen"]; 
      [coder encodeBool:bGameCompleted forKey:@"GameCompleted"]; 
      [coder encodeBool:bGameOver forKey:@"GameOver"]; 
     } 
     else 
     { 
      [coder encodeObject:strCompleteWord]; 
      [coder encodeObject:strWordToGuess]; 
      [coder encodeObject:arGuessedLetters]; 
      //[coder encodeObject:arGuessedLettersPos]; 
      [coder encodeValueOfObjCType:@encode(NSInteger) at:&iScore]; 
      [coder encodeValueOfObjCType:@encode(NSInteger) at:&iLives]; 
      [coder encodeValueOfObjCType:@encode(NSInteger) at:&iRocksFallen]; 
      [coder encodeValueOfObjCType:@encode(BOOL) at:&bGameCompleted]; 
      [coder encodeValueOfObjCType:@encode(BOOL) at:&bGameOver]; 
     } 
    } 

그리고 보관 및 보관 해제 데이터 이러한 방법을 사용

두 가지 문제점이 있습니다.

1) arGuessedLettersPos이있는 행은 주석 처리됩니다. 왜냐하면이 배열을 인코딩 할 때마다 오류가 발생하고 (이 아카이버는 구조체를 인코딩 할 수 없기 때문입니다.)이 배열은 CGRect 구조체를 저장하는 데 사용됩니다. 인터넷에서 솔루션을 보았습니다. 배열의 각 CGRectNSString (NSStringFromCGRect() 사용)으로 변환 된 다음 저장됩니다. 좋은 접근인가?

2) 이것은 나를 위해 더 큰 문제입니다. 이 줄에 주석을 달고 코드를 성공적으로 실행 한 다음 데이터를 저장 (보관) 한 다음로드 (보관 해제)하려고하면 데이터가로드되지 않습니다. 오류가 없지만 currentGame 개체에로드해야하는 데이터가 없습니다.

제게 조언 해 주시겠습니까? 이것은 처음으로 아카이브와 아카이브를 사용하고 있습니다.

답장을 보내 주셔서 감사합니다.

답변

1

내가 누락되었지만이 코드에서 분명한 버그가 보이지 않습니다. 당신의 인코딩/디코딩 방법이 있는지 (엑스 코드의 명령 변화-R로 열립니다) 디버그 출력을

  • 일부 NSLog 문을 추가하고 시계 : 여기

    은 도움이 될 몇 가지 아이디어입니다 실제로 호출됩니다.
  • 보관 파일이 저장되어 있는지 확인 : 시뮬레이터에서 실행 중이면/tmp/my_archive_file과 같이 원하는 로컬 경로에 저장할 수 있습니다. 그 파일에 저장하려고 시도하고, (a) 파일이 올바른 타임 스탬프와 함께 존재하는지, 그리고 (b) 파일을 출력하는지, 이진 gooblygoo 사이에서 인식 가능한 문자열 (예 : "RocksFallen")을 볼 수 있습니다.

나는 또한 당신이 항상 명시 적으로 당신을 위해 당신의 더러운 일을하는 NSKeyed(Un)archiver을 사용할 때 사실 일 것 알고 있기 때문에 allowsKeyed(En)coding를 확인하기 위해 필요한 생각하지 않습니다. 따라서 코드의 나머지 절반을 버릴 수 있습니다.

CGRect의 배열 코딩에 대해 : NSMutableArray에 구조체를 직접 추가 할 수 있다고 생각하지 않습니까? 따라서 이어야합니다. 즉, NSCoding을 해당 개체에 추가 할 수 있습니다. 자신의 개체가 아닌 경우 하위 클래스로 만들고 해당 프로토콜을 추가하거나 범주로 추가 할 수 있습니다.

0

답장을 보내 주셔서 감사합니다.

저장된 파일을보고 RocksFallen과 같은 인식 가능한 문자열이 있고 문자열 변수에 저장할 수있는 인식 가능한 값도 있습니다.이 점이 좋습니다.

코드에 NSLog를 넣으려고했는데 모든 것이 좋지 않은 것 같습니다. 그래서 ... 처음으로 시뮬레이터를 시작하면 아무 것도 저장되지 않으므로 아카이브 파일이 없습니다. 그렇습니다. 그런 다음 무언가를 변경하고 응용 프로그램을 종료하십시오. 응용 프로그램이 종료되면 데이터가 보관 될 수 있으며 모든 것이 정상입니다. NSLog 문은 콘솔에 기록되고 파일은 디스크에 기록됩니다. 하지만 이상한 점은 응용 프로그램을 시작할 때 디코딩 메서드 (initwithcoder)가 호출되지 않는다는 것입니다. 이유를 모르겠습니다. 그런 다음 시뮬레이터를 종료하고 시뮬레이터를 다시 실행합니다. 다시 실행하면 디코딩 메소드가 실행될 때 호출됩니다. 하지만 시뮬레이터를 실행 한 후 첫 번째 실행 시간에만, 마치 앱을 종료하고 다시 실행하는 것과 같은 시뮬레이터로 작업 할 때 initWithCoder 메소드가 호출되지 않고 그 것이 매우 이상합니다.

그래서 아카이브를 저장하는 데 문제가 있습니다. 생각한다.

+0

당신은 여기서 좋은 단서를 가지고있는 것처럼 들립니다. 코드 내에서 원하는 파일이 있는지 확인할 수 있습니다. 임시 위치에 저장되었거나 파일 이름에 오타가있을 수 있습니다. 또 다른 아이디어는 unarchiveObjectWithFile에 대한 호출 바로 전에 NSLog를 추가하여 정확한 행이 실행 중인지 확인하는 것입니다. 모험을 느끼는 경우, 거기에 중단 점을 추가하고 코드를 살펴볼 수 있습니다. – Tyler

2

로드의 문제와 다른 방법으로 해결 저장 중 ... 대신 구현

- (ID) initWithCoder : (NSCoder ) 코더와 - (무효) encodeWithCoder : (NSCoder는) 코더 나는이 솔루션을 사용 :

NSMutableData *data = [NSMutableData alloc]; 
    NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data]; 

    [archiver encodeObject:self.strCompleteWord forKey:@"CompleteWord"]; 
    [archiver encodeObject:self.strWordToGuess forKey:@"WordToGuess"]; 
    [archiver encodeObject:self.arGuessedLetters forKey:@"GuessedLetters"]; 
    //[coder encodeObject:self.arGuessedLettersPos forKey:@"GuessedLettersPos"]; 
    [archiver encodeInteger:self.iScore forKey:@"Score"]; 
    [archiver encodeInteger:self.iLives forKey:@"Lives"]; 
    [archiver encodeInteger:self.iRocksFallen forKey:@"RocksFallen"]; 
    [archiver encodeBool:self.bGameCompleted forKey:@"GameCompleted"]; 
    [archiver encodeBool:self.bGameOver forKey:@"GameOver"]; 

    [archiver finishEncoding]; 

    [data writeToFile:strPath atomically:YES]; 

    [data release]; 

NSMutableData *data = [[NSMutableData alloc] initWithContentsOfFile:strPath]; 
    NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data]; 

    self.strCompleteWord = [[unarchiver decodeObjectForKey:@"CompletedWord"] copy]; 
    self.strWordToGuess = [[unarchiver decodeObjectForKey:@"WordToGuess"] copy]; 
    self.arGuessedLetters = [[unarchiver decodeObjectForKey:@"GuessedLetters"] retain]; 
    //self.arGuessedLettersPos = [[unarchiver decodeObjectForKey:@"GuessedLettersPos"] retain];  
    self.iScore = [unarchiver decodeIntegerForKey:@"Score"]; 
    self.iLives = [unarchiver decodeIntegerForKey:@"Lives"]; 
self.iRocksFallen = [unarchiver decodeIntegerForKey:@"RocksFallen"]; 
    self.bGameCompleted = [unarchiver decodeBoolForKey:@"GameCompleted"]; 
    self.bGameOver = [unarchiver decodeBoolForKey:@"GameOver"]; 

    [unarchiver finishDecoding]; 
    [data release]; 

그리고 이것은 완전히 잘 :)

,691를 작동
0

(포인터가없는) 구조체를 보관하는 가장 좋은 방법은 NSData 블록에 값을 래핑하는 것입니다.

for (int i = 0; i < items; i++) { 

    NSString *keyValue = [NSString stringWithFormat:@"YourStruct%i", i ]; 
    NSData *dataset = [NSData dataWithBytes:(void*)&activeprofile[i] length:(sizeof(profileset))]; 

    [encoder encodeObject:dataset forKey:keyValue]; // makes a nice, solid data block 

} 

하고 다시 데이터를 읽기 : 여기

, 내가 아카이버에 구조체의 배열을 덤핑하고있어이

for (int i = 0; i < items; i++) { 

    NSString *keyValue = [NSString stringWithFormat:@"YourStruct%i", i ]; 
    NSData *dataset = [decoder decodeObjectForKey:keyValue]; 

    [dataset getBytes:&activeprofile[i] length:sizeof(profileset)]; 

} 

당신은 그것을 가지고 : 파이로 쉽고에 매우 유연한 데이터 유형!

비 키잉 보관과 유사한 방법은 여기에서 찾을 수 있습니다. http://borkware.com/quickies/one?topic=NSCoder NSArchive는 iPhone에서 지원되지 않으며 기존 코드로 분류되었으므로 키 보관 처리를 권장합니다.