iPhone序列化问题

iPhone序列化问题,iphone,cocoa-touch,serialization,Iphone,Cocoa Touch,Serialization,我需要将自己创建的类保存到文件中,我在互联网上发现,好的方法是使用NSKeyedArchiver和NSKeyedUnarchiver 我的类定义如下所示: @interface Game : NSObject <NSCoding> { NSMutableString *strCompleteWord; NSMutableString *strWordToGuess; NSMutableArray *arGuessedLetters; //This a

我需要将自己创建的类保存到文件中,我在互联网上发现,好的方法是使用NSKeyedArchiver和NSKeyedUnarchiver 我的类定义如下所示:

@interface Game : NSObject <NSCoding> {

    NSMutableString *strCompleteWord;
    NSMutableString *strWordToGuess;

    NSMutableArray *arGuessedLetters;    //This array stores characters
    NSMutableArray *arGuessedLettersPos;  //This array stores CGRects

    NSInteger iScore;
    NSInteger iLives;
    NSInteger iRocksFallen;

    BOOL bGameCompleted;
    BOOL bGameOver;
}
我使用这些方法来归档和取消归档数据:

[NSKeyedArchiver archiveRootObject:currentGame toFile:strPath];
Game *currentGame = [NSKeyedUnarchiver unarchiveObjectWithFile:strPath];
我有两个问题

1) 如您所见,带有
arGuessedLettersPos
的行会被注释,这是因为每次我尝试对该数组进行编码时,都会出现错误(该存档程序无法对结构进行编码),并且该数组用于存储CGRect结构。 我在互联网上看到了解决方案。问题是,数组中的每个
CGRect
都转换为
NSString
(使用
NSStringFromCGRect()
)然后保存。这是一个好方法吗

2) 这对我来说是个更大的问题。即使我注释这一行,然后成功运行代码,然后保存(归档)数据,然后尝试加载(取消归档)它们,也不会加载任何数据。没有任何错误,但
currentGame
对象没有应加载的数据

你能给我一些建议吗?这是我第一次使用Archiver和UnArchiver


非常感谢您的每一个回复。

我可能会错过它,但我没有在这段代码中看到任何明显的错误

以下是一些可能有帮助的想法:

  • 添加一些NSLog语句,并观察调试输出(在xcode中使用command-shift-R打开),以查看是否实际调用了编码/解码方法
  • 检查存档文件是否已保存:在模拟器中运行时,您可以保存到所需的任何本地路径,例如/tmp/my_archive_file。尝试保存到该文件,并查看(a)该文件是否具有正确的时间戳,(b)打印出该文件,您可以在二进制gooblygoo中看到一些可识别的字符串(如“RocksFallen”)
我也不认为有必要检查
allowskyed(En)编码
,因为你知道当你明确使用
NSKeyed(Un)archiver为你做肮脏的工作时,这总是正确的。因此,您可以扔掉代码的另一半


关于对
CGRect
s的数组进行编码:我认为您不能直接将结构添加到
NSMutableArray
,对吗?因此,它们必须是某种对象,这意味着您可以向该对象添加
NSCoding
支持。如果它不是您自己的对象,您可以将其子类化并添加该协议,或者尝试将其作为一个类别添加。

感谢回复泰勒

我查看了保存的文件,其中有一些可识别的字符串,如RocksFallen等,还有一些可识别的值可能保存在字符串变量中。。所以这看起来不错

我试着在代码中加入一些nslog,但并不是所有的东西都是好的。所以 当我第一次启动模拟器时,没有存档文件,是的,很明显,因为没有保存任何文件。然后我更改一些内容并退出应用程序。当应用程序终止时,数据可能会被归档,一切正常。NSLog语句写在控制台中,文件在磁盘上。但奇怪的是,当我启动应用程序时,没有调用decode方法(initwithcoder)。。不知道为什么。然后我退出模拟器并再次运行模拟器。当我再次运行它时,会在启动时调用decode方法。但只有在运行模拟器后的第一次启动时,当我使用模拟器(如退出应用程序并再次运行)时,initWithCoder方法才没有被调用,这对我来说非常奇怪


因此,我认为在取消归档时存在一些问题。

加载和保存的问题用另一种方法解决了

我没有实现-(id)initWithCoder:(NSCoder)coder和-(void)encodeWithCoder:(NSCoder)coder,而是使用以下解决方案:

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


这样做非常好:)

用归档结构(不包含任何指针)的最佳方法是将值包装在NSData块中

在这里,我将向archiver转储一个结构数组:

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
并将数据读回:

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)];

}
for(int i=0;i
你已经做到了:简单如馅饼,数据类型极其灵活


在这里可以找到一种类似的非键控归档方法:尽管我建议坚持键控归档,因为iPhone不支持NSArchive,它被归类为遗留代码。

听起来你有一些很好的线索可以利用。您可以在代码中检查所需文件是否存在。它可能被保存在临时位置,或者文件名中可能有键入错误等。另一种方法是在调用unarchiveObjectWithFile之前添加一个NSLog:检查是否正在执行该行。如果您感到有冒险精神,可以在那里添加一个断点,然后遍历代码。
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)];

}