145

我想将一个NSMutableDictionary对象保存在NSUserDefaults. 中的键类型NSMutableDictionaryNSString,值类型是NSArray,其中包含实现的对象列表NSCoding。每个文档,NSString并且NSArray两者都符合NSCoding.

我收到此错误:

[NSUserDefaults setObject: forKey:]: 尝试插入 NSCFDictionary 类的非属性值....

4

6 回答 6

230

我发现了一种替代方法,在保存之前,我使用以 .结尾的根对象(NSArray对象)进行编码。然后使用 UserDefaults 保存.NSKeyedArchiverNSDataNSData

当我需要数据时,我读出NSData, 并用它NSKeyedUnarchiver来转换NSData回对象。

这有点麻烦,因为我NSData每次都需要转换为/从,但它确实有效。

以下是每个请求的一个示例:

节省:

NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSMutableArray *arr = ... ; // set value
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:arr];
[defaults setObject:data forKey:@"theKey"];
[defaults synchronize];

加载:

NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSData *data = [defaults objectForKey:@"theKey"];
NSArray *arr = [NSKeyedUnarchiver unarchiveObjectWithData:data];

数组中的元素实现

@interface CommentItem : NSObject<NSCoding> {
    NSString *value;
}

然后在实现中CommentItem,提供了两种方法:

-(void)encodeWithCoder:(NSCoder *)encoder
{
    [encoder encodeObject:value forKey:@"Value"];
}

-(id)initWithCoder:(NSCoder *)decoder
{
    self.value = [decoder decodeObjectForKey:@"Value"];
    return self;
}

有人有更好的解决方案吗?

谢谢大家。

于 2009-01-23T04:56:44.447 回答
105

如果您将对象保存在用户默认值中,则所有对象,递归地,一直向下,必须是属性列表对象。符合 NSCoding 在这里没有任何意义——NSUserDefaults不会自动将它们编码为NSData,你必须自己做。如果您的“实现的对象列表NSCoding”表示不是属性列表对象的对象,那么您必须在保存为用户默认值之前对它们进行处理。

仅供参考,属性列表类是NSDictionaryNSArrayNSStringNSDateNSDataNSNumber。您可以将可变子类(如NSMutableDictionary)写入用户首选项,但您读出的对象将始终是不可变的。

于 2009-01-23T04:44:19.607 回答
14

您的所有键都在字典中NSString吗?我认为他们必须是为了将字典保存到属性列表中。

于 2009-01-23T04:38:59.070 回答
8

最简单的答案:

NSDictionary只是一个plist 对象,如果键是 NSStrings。因此,将“密钥”NSString.stringWithFormat


解决方案 :

NSString *key = [NSString stringWithFormat:@"%@",[dictionary valueForKey:@"Key"]];

好处 :

  1. 它将添加String-Value
  2. 当您的变量值为 时,它将添加空值NULL
于 2013-02-04T09:11:17.937 回答
5

您是否考虑过实施该NSCoding协议?这将允许您在 iPhone 上使用两种简单的方法进行编码和解码,这些方法使用NSCoding. 首先,您需要将 添加NSCoding到您的类中。

这是一个例子:

这是在 .h 文件中

@interface GameContent : NSObject <NSCoding>

然后你需要实现 NSCoding 协议的两种方法。

    - (id) initWithCoder: (NSCoder *)coder
    {
        if (self = [super init])
        {
               [self setFoundHotSpots:[coder decodeObjectForKey:@"foundHotSpots"]];
        }
        return self;
    }

    - (void) encodeWithCoder: (NSCoder *)coder
    {
           [coder encodeObject:foundHotSpots forKey:@"foundHotSpots"];
    }

查看 NSCoder 上的文档以获取更多信息。这对于我的项目来说非常方便,如果应用程序关闭,我需要在 iPhone 上保存应用程序的状态,并在重新打开时将其恢复到它的状态。

关键是将协议添加到接口中,然后实现属于NSCoding.

我希望这有帮助!

于 2009-01-25T17:34:20.680 回答
0

没有更好的解决方案。另一种选择是将编码对象保存到磁盘 - 但这是做同样的事情。他们都以 NSData 结束,当你想要它回来时,它会被解码。

于 2009-01-24T00:47:49.347 回答