解码ObjectForKey:始终返回nil

发布于 2025-01-08 07:56:58 字数 4792 浏览 0 评论 0原文

我试图将对象图保存到文件中,然后稍后重新加载它,但是对于我指定的任何键,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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

白昼 2025-01-15 07:56:58

您使用单个根对象进行序列化,但尝试使用该级别不存在的密钥进行反序列化。

您需要 unarchiveObjectWithData:,如下所示:

NSData *codedData = [[[NSData alloc] initWithContentsOfFile:pathAndFileName] autorelease];
PSYDefaults *decodedDefaults = [NSKeyedUnarchiver unarchiveObjectWithData:codedData];

请注意,您还需要实现 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:

NSData *codedData = [[[NSData alloc] initWithContentsOfFile:pathAndFileName] autorelease];
PSYDefaults *decodedDefaults = [NSKeyedUnarchiver unarchiveObjectWithData:codedData];

Note that you'll also need to implement initWithCoder: as counterpart to encodeWithCoder:. 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 your encodeWithCoder: (but you should give it a different name then). Then you'd write a counterpart which reads the fields back via a NSKeyedUnarchiver where you do use decodeObjectForKey: and friends for each field.

You also might want to read Apple's Archives and Serializations Programming Guide.

執念 2025-01-15 07:56:58

尝试使用以下方法保存您的对象:

[NSKeyedArchiver archiveRootObject:object toFile:filePath];

并使用以下方法加载它:

[NSKeyedUnarchiver unarchiveObjectWithFile:filePath];

我使用上述方法将带有自定义对象的 NSDictionary 保存到文件中。

而且你的对象中应该有 initWithCoder:(NSCoder *)decoder 函数。
使用哪个解码数据

[decoder decodeObjectFoyKey:yourKey];

Try to save your object using:

[NSKeyedArchiver archiveRootObject:object toFile:filePath];

and load it using:

[NSKeyedUnarchiver unarchiveObjectWithFile:filePath];

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

[decoder decodeObjectFoyKey:yourKey];
人事已非 2025-01-15 07:56:58

我在使用 FXForm 时遇到了 NSCoder decodeObjectForKey 方法的另一个问题 - 它崩溃了,没有任何解释。

- (id)initWithCoder:(NSCoder *)decoder
{
  if (self = [super init]) {
    self.someObject = [decoder decodeObjectForKey:@"someObject"];
  }
  return self;
}

原因是内存问题。通常,看起来当日志中没有对错误的解释时,这意味着这是一个内存问题。我忘记使用正确的属性属性 - 复制。我用分配代替。这是正确的代码:

@interface MyClass : : NSObject <FXForm, NSCoding>

@property (nonatomic, copy) SomeClass *someObject;

@end

以防万一有人也遇到这个问题。

I had another problem with NSCoder's decodeObjectForKey method while using FXForm - it crashed without any explanation.

- (id)initWithCoder:(NSCoder *)decoder
{
  if (self = [super init]) {
    self.someObject = [decoder decodeObjectForKey:@"someObject"];
  }
  return self;
}

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:

@interface MyClass : : NSObject <FXForm, NSCoding>

@property (nonatomic, copy) SomeClass *someObject;

@end

Just in case somebody meets this problem too.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文