解码ObjectForKey:始终返回nil
我试图将对象图保存到文件中,然后稍后重新加载它,但是对于我指定的任何键,decodeObjectForKey: 总是返回 nil 。
创建了一个二进制文件,其中偶尔包含人类可读的文本,即 titleTextColor,因此我认为归档过程正在运行。
我是否误解了 NSKeyedArchiver 和 NSKeyedUnarchiver 的工作原理?任何帮助将不胜感激。
- (void)encodeWithCoder:(NSCoder *)encoder {
[encoder encodeFloat:titleFontSize forKey:@"titleFontSize"];
[encoder encodeObject:[UIColor orangeColor] forKey:@"titleTextColor"];
[encoder encodeObject:lineSeparatorColor forKey:@"lineSeparatorColor"];
[encoder encodeObject:bodyTextColor forKey:@"bodyTextColor"];
[encoder encodeFloat:bodyTextFontSize forKey:@"bodyTextFontSize"];
[encoder encodeObject:backgroundColor forKey:@"backgroundColor"];
[encoder encodeObject:tintColor forKey:@"tintColor"];
[encoder encodeInteger:bodyTextAlignment forKey:@"bodyTextAlignment"];
[encoder encodeObject:@"Text" forKey:@"Text"];
}
+ (void) saveToFile {
// Get the shared instance
PSYDefaults *sharedInstance = [PSYDefaults sharedInstance];
// Serialise the object
NSData *serializedObject = [NSKeyedArchiver archivedDataWithRootObject:sharedInstance];
// Get the path and filename of the file
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *pathAndFileName = [documentsDirectory stringByAppendingPathComponent:ksDefaultsFileName];
// Write the defaults to a file
if (serializedObject) [serializedObject writeToFile:pathAndFileName atomically:YES];
}
+ (void) loadFromFile {
// Get the shared instance
PSYDefaults *sharedInstance = [PSYDefaults sharedInstance];
// Get the path and filename of the file
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *pathAndFileName = [documentsDirectory stringByAppendingPathComponent:ksDefaultsFileName];
NSData *codedData = [[[NSData alloc] initWithContentsOfFile:pathAndFileName] autorelease];
NSKeyedUnarchiver *defaults = [[NSKeyedUnarchiver alloc] initForReadingWithData:codedData];
// Set the properties of the shared instance
NSString *test = [defaults decodeObjectForKey:@"Text"];
NSLog (@"%@", test);
sharedInstance.titleTextColor = [defaults decodeObjectForKey:@"titleTextColor"];
[defaults release];
}
编辑:基于 DarkDust 的建议:
- (id)initWithCoder:(NSCoder *)aDecoder {
self = [super init];
if (self) {
self.titleFontSize = [[aDecoder decodeObjectForKey:@"titleFontSize"] floatValue];
self.titleTextColor = [aDecoder decodeObjectForKey:@"titleTextColor"];
self.lineSeparatorColor = [aDecoder decodeObjectForKey:@"lineSeparatorColor"];
self.bodyTextColor = [aDecoder decodeObjectForKey:@"bodyTextColor"];
self.bodyTextFontSize = [[aDecoder decodeObjectForKey:@"bodyTextFontSize"] floatValue];
self.backgroundColor = [aDecoder decodeObjectForKey:@"backgroundColor"];
self.tintColor = [aDecoder decodeObjectForKey:@"tintColor"];
self.bodyTextAlignment = [[aDecoder decodeObjectForKey:@"bodyTextAlignment"] intValue];
}
return self;
}
并创建一个新实例来测试:
+ (void) loadFromFile {
// Get the shared instance
PSYDefaults *sharedInstance = [PSYDefaults sharedInstance];
// Get the path and filename of the file
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *pathAndFileName = [documentsDirectory stringByAppendingPathComponent:ksDefaultsFileName];
NSData *codedData = [[[NSData alloc] initWithContentsOfFile:pathAndFileName] autorelease];
PSYDefaults *newInstance = [NSKeyedUnarchiver unarchiveObjectWithData:codedData];
sharedInstance.titleTextColor = newInstance.titleTextColor;
}
编辑 - 更新(需要将浮点数和整数编码为 NSNumbers)
- (void)encodeWithCoder:(NSCoder *)encoder {
[encoder encodeObject:[NSNumber numberWithFloat:titleFontSize] forKey:@"titleFontSize"];
[encoder encodeObject:titleTextColor forKey:@"titleTextColor"];
[encoder encodeObject:lineSeparatorColor forKey:@"lineSeparatorColor"];
[encoder encodeObject:bodyTextColor forKey:@"bodyTextColor"];
[encoder encodeObject:[NSNumber numberWithFloat:bodyTextFontSize] forKey:@"bodyTextFontSize"];
[encoder encodeObject:backgroundColor forKey:@"backgroundColor"];
[encoder encodeObject:tintColor forKey:@"tintColor"];
[encoder encodeObject:[NSNumber numberWithInt:bodyTextAlignment] forKey:@"bodyTextAlignment"];
}
I am trying to save my object graph to a file and then reload it at a later time, however decodeObjectForKey: always returns nil for any key I specify.
A binary file is created and does have the occasional human readable text in it, i.e., titleTextColor so I think the archiving process is working.
Have I miss-understood how NSKeyedArchiver and NSKeyedUnarchiver work? Any help would be appreciated.
- (void)encodeWithCoder:(NSCoder *)encoder {
[encoder encodeFloat:titleFontSize forKey:@"titleFontSize"];
[encoder encodeObject:[UIColor orangeColor] forKey:@"titleTextColor"];
[encoder encodeObject:lineSeparatorColor forKey:@"lineSeparatorColor"];
[encoder encodeObject:bodyTextColor forKey:@"bodyTextColor"];
[encoder encodeFloat:bodyTextFontSize forKey:@"bodyTextFontSize"];
[encoder encodeObject:backgroundColor forKey:@"backgroundColor"];
[encoder encodeObject:tintColor forKey:@"tintColor"];
[encoder encodeInteger:bodyTextAlignment forKey:@"bodyTextAlignment"];
[encoder encodeObject:@"Text" forKey:@"Text"];
}
+ (void) saveToFile {
// Get the shared instance
PSYDefaults *sharedInstance = [PSYDefaults sharedInstance];
// Serialise the object
NSData *serializedObject = [NSKeyedArchiver archivedDataWithRootObject:sharedInstance];
// Get the path and filename of the file
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *pathAndFileName = [documentsDirectory stringByAppendingPathComponent:ksDefaultsFileName];
// Write the defaults to a file
if (serializedObject) [serializedObject writeToFile:pathAndFileName atomically:YES];
}
+ (void) loadFromFile {
// Get the shared instance
PSYDefaults *sharedInstance = [PSYDefaults sharedInstance];
// Get the path and filename of the file
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *pathAndFileName = [documentsDirectory stringByAppendingPathComponent:ksDefaultsFileName];
NSData *codedData = [[[NSData alloc] initWithContentsOfFile:pathAndFileName] autorelease];
NSKeyedUnarchiver *defaults = [[NSKeyedUnarchiver alloc] initForReadingWithData:codedData];
// Set the properties of the shared instance
NSString *test = [defaults decodeObjectForKey:@"Text"];
NSLog (@"%@", test);
sharedInstance.titleTextColor = [defaults decodeObjectForKey:@"titleTextColor"];
[defaults release];
}
EDIT: Based on advice from DarkDust:
- (id)initWithCoder:(NSCoder *)aDecoder {
self = [super init];
if (self) {
self.titleFontSize = [[aDecoder decodeObjectForKey:@"titleFontSize"] floatValue];
self.titleTextColor = [aDecoder decodeObjectForKey:@"titleTextColor"];
self.lineSeparatorColor = [aDecoder decodeObjectForKey:@"lineSeparatorColor"];
self.bodyTextColor = [aDecoder decodeObjectForKey:@"bodyTextColor"];
self.bodyTextFontSize = [[aDecoder decodeObjectForKey:@"bodyTextFontSize"] floatValue];
self.backgroundColor = [aDecoder decodeObjectForKey:@"backgroundColor"];
self.tintColor = [aDecoder decodeObjectForKey:@"tintColor"];
self.bodyTextAlignment = [[aDecoder decodeObjectForKey:@"bodyTextAlignment"] intValue];
}
return self;
}
and creating a new instance just to test:
+ (void) loadFromFile {
// Get the shared instance
PSYDefaults *sharedInstance = [PSYDefaults sharedInstance];
// Get the path and filename of the file
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *pathAndFileName = [documentsDirectory stringByAppendingPathComponent:ksDefaultsFileName];
NSData *codedData = [[[NSData alloc] initWithContentsOfFile:pathAndFileName] autorelease];
PSYDefaults *newInstance = [NSKeyedUnarchiver unarchiveObjectWithData:codedData];
sharedInstance.titleTextColor = newInstance.titleTextColor;
}
EDIT - Update (needed to encode floats and ints as NSNumbers)
- (void)encodeWithCoder:(NSCoder *)encoder {
[encoder encodeObject:[NSNumber numberWithFloat:titleFontSize] forKey:@"titleFontSize"];
[encoder encodeObject:titleTextColor forKey:@"titleTextColor"];
[encoder encodeObject:lineSeparatorColor forKey:@"lineSeparatorColor"];
[encoder encodeObject:bodyTextColor forKey:@"bodyTextColor"];
[encoder encodeObject:[NSNumber numberWithFloat:bodyTextFontSize] forKey:@"bodyTextFontSize"];
[encoder encodeObject:backgroundColor forKey:@"backgroundColor"];
[encoder encodeObject:tintColor forKey:@"tintColor"];
[encoder encodeObject:[NSNumber numberWithInt:bodyTextAlignment] forKey:@"bodyTextAlignment"];
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
您使用单个根对象进行序列化,但尝试使用该级别不存在的密钥进行反序列化。
您需要
unarchiveObjectWithData:
,如下所示:请注意,您还需要实现
initWithCoder:
作为encodeWithCoder:
的对应项。尽管您似乎希望在这里有一个单例,但由于[NSKeyedArchiver archivedDataWithRootObject:sharedInstance]
,NSCoding 要求在这里创建一个新对象。如果您想在不创建 PSYDefaults 的新实例的情况下对字段进行编码/解码,则需要使用 -[NSKeyedArchiver initForWritingWithMutableData:] 并传递它归档到类似于您的
encodeWithCoder:
的方法(但您应该给它一个不同的名称)。然后,您将编写一个对应项,通过NSKeyedUnarchiver
读回字段,其中您对每个字段使用decodeObjectForKey:
和朋友。您可能还想阅读 Apple 的 档案和序列化编程指南。
You serialized using a single root object, but you try to deserialize using a key which doesn't exist at that level.
You want
unarchiveObjectWithData:
, as in:Note that you'll also need to implement
initWithCoder:
as counterpart toencodeWithCoder:
. Even though it seems you want to have a singleton here, NSCoding demands to create a new object here due to[NSKeyedArchiver archivedDataWithRootObject:sharedInstance]
.If you want to en/decode the fields without creating a new instance of
PSYDefaults
, then you need to use -[NSKeyedArchiver initForWritingWithMutableData:] and pass that archive to a method similar to yourencodeWithCoder:
(but you should give it a different name then). Then you'd write a counterpart which reads the fields back via aNSKeyedUnarchiver
where you do usedecodeObjectForKey:
and friends for each field.You also might want to read Apple's Archives and Serializations Programming Guide.
尝试使用以下方法保存您的对象:
并使用以下方法加载它:
我使用上述方法将带有自定义对象的 NSDictionary 保存到文件中。
而且你的对象中应该有 initWithCoder:(NSCoder *)decoder 函数。
使用哪个解码数据
Try to save your object using:
and load it using:
I use above methods to save NSDictionary with custom object to a file.
And also you should have the function initWithCoder:(NSCoder *)decoder in your object.
Which decode the data using
我在使用
FXForm
时遇到了NSCoder
decodeObjectForKey
方法的另一个问题 - 它崩溃了,没有任何解释。原因是内存问题。通常,看起来当日志中没有对错误的解释时,这意味着这是一个内存问题。我忘记使用正确的属性属性 - 复制。我用分配代替。这是正确的代码:
以防万一有人也遇到这个问题。
I had another problem with
NSCoder's
decodeObjectForKey
method while usingFXForm
- it crashed without any explanation.The reason was in memory issues. Commonly, looks like when there is no explanation of a bug in logs, it means, it's a memory issue. I forgot to use correct property attribute - copy. I used assign instead. This is correct code:
Just in case somebody meets this problem too.