2009-08-11 16 views
3

実装方法initWithCoder:encodeWithCoder:この方法:iPhoneのシリアル化の問題

- (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]; 
     } 
    } 

そして私は、アーカイブおよびアーカイブしないデータこれらのメソッドを使用します

私には2つの問題があります。この配列をエンコードしようとするたびにエラーが発生します(このアーカイバは構造体をエンコードできません)。この配列はCGRect構造体を格納するために使用されるため、arGuessedLettersPosの行がコメントされています。 私はインターネット上で解決策を見ました。つまり、配列内のCGRectはすべてNSStringNSStringFromCGRect()を使用)に変換されて保存されます。それは良いアプローチですか?

2)これは私にとって大きな問題です。この行をコメントしてからコードを正常に実行してから、データを保存(アーカイブ)してから、それらをロード(アーカイブ解除)しようとしても、データはロードされません。エラーはありませんが、currentGameオブジェクトにはロードする必要があるデータがありません。

お願いします。これはアーカイバとアーカイブを使用している初めてです。

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

答えて

1

私はそれを見逃しているかもしれませんが、このコードには明らかなバグはありません。ここで

は役立つかもしれないいくつかのアイデアです:

  • は、いくつかのNSLogステートメントを追加し、あなたのエンコード/デコード方法があるかどうかを確認するためにデバッグ出力を(Xcodeでコマンド+ Shift + Rで開く)を見ます実際に呼び出されます。
  • アーカイブファイルが保存されていることを確認してください。:シミュレータで実行中で、/ tmp/my_archive_fileなどの任意のローカルパスに保存できます。そのファイルに保存し、(a)ファイルが正しいタイムスタンプで存在するかどうか、(b)ファイルをプリントアウトする場合、バイナリgooblygooの中で認識可能な文字列(「RocksFallen」など)を見ることができます。

私はまた、あなたが明示的にあなたのために汚い仕事をするためにNSKeyed(Un)archiverを使用しているときには常にtrueになるだろう知っているので、それはallowsKeyed(En)codingをチェックする必要はないと思います。だから、コードのもう半分を捨てることができます。

CGRectの配列のコーディングについて:NSMutableArrayに構造体を直接追加することはできないと思いますか?したがって、のオブジェクトでなければなりません。つまり、そのオブジェクトにNSCodingのサポートを追加できます。独自のオブジェクトでない場合は、サブクラス化してそのプロトコルを追加するか、カテゴリとして追加してみてください。

0

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

私は保存されたファイルを見て、RocksFallenのような認識可能な文字列があります。また、文字列変数に保存される認識可能な値もあります。これは良いと思われます。

私はコードにいくつかのNSLogを入れようとしましたが、すべてが良いとは思われませんでした。だから... 初めてシミュレータを起動すると、アーカイブファイルがないので、何も保存されていないので、明らかです。その後、何かを変更してアプリケーションを終了します。アプリケーションが終了すると、データがアーカイブされ、すべて正常です。 NSLogステートメントはコンソールに書き込まれ、ファイルはディスクに書き込まれます。しかし、奇妙なのは、アプリケーションを起動すると、デコードメソッド(initwithcoder)が呼び出されていないということです。理由はわかりません。次に、シミュレータを終了してシミュレータを再実行します。もう一度実行すると、デコードメソッドが起動時に呼び出されます。しかし、シミュレータを実行した後の最初の起動時にのみ、アプリケーションを終了して再度実行すると、initWithCoderメソッドは呼び出されず、私にとっては非常に奇妙です。

したがって、思う。

+0

ここでは、うまくいく手がかりがあるようです。 コード内で目的のファイルが存在することを確認できます。一時的な場所に保存されているかもしれないし、ファイル名の入力ミスなどがあるかもしれません。もう一つのアイデアは、una​​rchiveObjectWithFileへの呼び出しの前に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]; 

そして、これは:)

完全に正常に動作します
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ではサポートされていないため、レガシーコードとして分類されているため、キー付きアーカイブを使用することをおすすめします。