【问题标题】:decodeObjectForKey: always returns nildecodeObjectForKey:总是返回 nil
【发布时间】:2012-02-24 09:04:27
【问题描述】:

我正在尝试将我的对象图保存到一个文件中,然后稍后重新加载它,但是 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;
}

编辑 - 更新(需要将浮点数和整数编码为 NSNumber)

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

【问题讨论】:

    标签: iphone ios nskeyedarchiver nscoding


    【解决方案1】:

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

    你想要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 的 Archives and Serializations Programming Guide

    【讨论】:

    • 这是一个很好的建议,谢谢。我意识到取消归档是我的愚蠢行为,现在创建了一个新实例并实现了一个 initWithCoder。我想我快到了,当 NSKeyedUnarchiver 取消归档我的对象图时会调用 initWithCoder。但是,在调用 initWithCoder 任何想法后,我的访问权限不佳?戴夫
    • 噢,擦洗它。当 newInstance 已经自动释放时释放它是问题所在。感谢你的帮助!戴夫
    【解决方案2】:

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

    [NSKeyedArchiver archiveRootObject:object toFile:filePath];
    

    并使用以下方式加载它:

    [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];
    

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

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

    [decoder decodeObjectFoyKey:yourKey];
    

    【讨论】:

    • 感谢 Hanon,DarkDust 最终排序。为您的回答 +1 寻求帮助。
    【解决方案3】:

    我在使用 FXForm 时遇到了 NSCoder's 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
    

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

    【讨论】:

      猜你喜欢
      • 2017-03-28
      • 2015-03-05
      • 2014-08-25
      • 2016-05-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多