为什么 NSUserDefaults 在 iOS 中保存 NSMutableDictionary 失败?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/471830/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why NSUserDefaults failed to save NSMutableDictionary in iOS?
提问by BlueDolphin
I'd like to save an NSMutableDictionary
object in NSUserDefaults
. The key type in NSMutableDictionary
is NSString
, the value type is NSArray
, which contains a list of object which implements NSCoding
. Per document, NSString
and NSArray
both are conform to NSCoding
.
我想NSMutableDictionary
在NSUserDefaults
. 中的键类型NSMutableDictionary
是NSString
,值类型是NSArray
,其中包含一个实现的对象列表NSCoding
。每个文档,NSString
并且NSArray
两者都符合NSCoding
.
I am getting this error:
我收到此错误:
[NSUserDefaults setObject: forKey:]: Attempt to insert non-property value.... of class NSCFDictionary.
[NSUserDefaults setObject: forKey:]: Attempt to insert non-property value.... of class NSCFDictionary。
回答by BlueDolphin
I found out one alternative, before save, I encode the root object (NSArray
object) using NSKeyedArchiver
, which ends with NSData
. Then use UserDefaults save the NSData
.
我找到了一种替代方法,在保存之前,我使用 对根对象(NSArray
对象)进行编码NSKeyedArchiver
,以NSData
. 然后使用 UserDefaults 保存NSData
.
When I need the data, I read out the NSData
, and use NSKeyedUnarchiver
to convert NSData
back to the object.
当我需要数据时,我读出NSData
, 并用于NSKeyedUnarchiver
转换NSData
回对象。
It is a little cumbersome, because i need to convert to/from NSData
everytime, but it just works.
这有点麻烦,因为我NSData
每次都需要转换为/从,但它只是有效。
Here is one example per request:
以下是每个请求的一个示例:
Save:
节省:
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSMutableArray *arr = ... ; // set value
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:arr];
[defaults setObject:data forKey:@"theKey"];
[defaults synchronize];
Load:
加载:
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSData *data = [defaults objectForKey:@"theKey"];
NSArray *arr = [NSKeyedUnarchiver unarchiveObjectWithData:data];
The element in the array implements
数组中的元素实现
@interface CommentItem : NSObject<NSCoding> {
NSString *value;
}
Then in the implementation of CommentItem
, provides two methods:
然后在 的实现中CommentItem
,提供了两种方法:
-(void)encodeWithCoder:(NSCoder *)encoder
{
[encoder encodeObject:value forKey:@"Value"];
}
-(id)initWithCoder:(NSCoder *)decoder
{
self.value = [decoder decodeObjectForKey:@"Value"];
return self;
}
Anyone has better solution?
有人有更好的解决方案吗?
Thanks everyone.
谢谢大家。
回答by Tom Harrington
If you're saving an object in user defaults, all objects, recursively, all the way down, must be property list objects. Conforming to NSCoding doesn't mean anything here-- NSUserDefaults
won't automatically encode them into NSData
, you have to do that yourself. If your "list of object which implements NSCoding
" means objects that are not property list objects, then you'll have to do something with them before saving to user defaults.
如果您以用户默认值保存对象,则所有对象,递归地,一直向下,必须是属性列表对象。符合 NSCoding 在这里没有任何意义——NSUserDefaults
不会自动将它们编码为NSData
,你必须自己做。如果您的“实现的对象列表NSCoding
”意味着对象不是属性列表对象,那么您必须在保存到用户默认值之前对它们做一些事情。
FYI the property list classes are NSDictionary
, NSArray
, NSString
, NSDate
, NSData
, and NSNumber
. You can write mutable subclasses (like NSMutableDictionary
) to user preferences but the objects you read out will always be immutable.
FYI财产清单类NSDictionary
,NSArray
,NSString
,NSDate
,NSData
,和NSNumber
。您可以将可变子类(如NSMutableDictionary
)写入用户首选项,但您读出的对象将始终是不可变的。
回答by Sophie Alpert
Are all of your keys in the dictionary NSString
s? I think they have to be in order to save the dictionary to a property list.
你所有的键都在字典中NSString
吗?我认为他们必须是为了将字典保存到属性列表中。
回答by Bhavin
Simplest Answer :
最简单的答案:
NSDictionary
is only a plist object, if the keys are NSStrings.
So, Store the "Key"as NSString
with stringWithFormat
.
NSDictionary
只是一个plist 对象,如果键是 NSStrings。因此,存储的“钥匙”为NSString
用stringWithFormat
。
Solution :
解决方案 :
NSString *key = [NSString stringWithFormat:@"%@",[dictionary valueForKey:@"Key"]];
Benefits :
好处 :
- It will add String-Value.
- It will add Empty-Valuewhen your Value of Variable is
NULL
.
- 它将添加String-Value。
- 当您的变量值为 时,它将添加Empty-Value
NULL
。
回答by Niels Hansen
Have you considered looking at implementing the NSCoding
Protocol? This will allow you encode and decode on the iPhone with two simple methods that are implemented with the NSCoding
. First you would need to adding the NSCoding
to your Class.
您是否考虑过实施该NSCoding
协议?这将允许您使用NSCoding
. 首先,您需要将 加入NSCoding
到您的类中。
Here is an example:
下面是一个例子:
This is in the .h file
这是在 .h 文件中
@interface GameContent : NSObject <NSCoding>
Then you will need to implement two methods of the NSCoding Protocol.
然后你需要实现 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"];
}
Check out the documentation on NSCoder for more information. That has come in really handy for my projects where I need to save the state of the application on the iPhone if the application is closed and restore it back to it's state when its back on.
查看 NSCoder 上的文档以获取更多信息。这对于我的项目来说非常方便,如果应用程序关闭,我需要在 iPhone 上保存应用程序的状态,并在它重新打开时将其恢复到它的状态。
The key is to add the protocol to the interface and then implement the two methods that are part of NSCoding
.
关键是将协议添加到接口中,然后实现属于NSCoding
.
I hope this helps!
我希望这有帮助!
回答by Dan Keen
There is no better solution. Another option would be to just save the coded object to disk - but that is doing the same thing. They both end up with NSData that gets decoded when you want it back.
没有更好的解决方案。另一种选择是将编码对象保存到磁盘 - 但这是做同样的事情。它们都以 NSData 结束,当你想要它时它会被解码。