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