使用 NSUserDefaults 保存 NSMutableArray 不起作用

Posted

技术标签:

【中文标题】使用 NSUserDefaults 保存 NSMutableArray 不起作用【英文标题】:Saving a NSMutableArray using NSUserDefaults not working 【发布时间】:2012-05-04 06:54:50 【问题描述】:

我有一个名为 myWallet 的可变数组及其属性声明:

@property (nonatomic, strong) NSMutableArray *myWallet;

这个数组被 Cards 填充,它是一个对象。我从另一个视图控制器创建了一个卡片的新实例,因此我使用委托方法能够在我的初始视图控制器(表视图控制器)上传递这个创建的卡片。下面是委托方法

- (void)addCardViewController:(AddCardViewController *)sender didCreateCard:(Card *)newCard

    // insert a new card

    self.myCard = newCard;
    [self.myWallet addObject:self.myCard];

    [self.tableView reloadData];

到目前为止,我可以创建 Card 的新实例,当我这样做时,一个新的表格单元格会出现在我的初始视图控制器 (Card Wallet VC) 中。

我想要的是当用户完成使用应用程序时,他/她之前创建的 Card 的创建实例仍然出现在应用程序的下一次运行时。所以我使用 NSUserDefaults 来做到这一点。下面的方法是我使用 NSUserDefaults 来保存的。

- (void)saveMyWallet


    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];

    [defaults setObject:self.myWallet forKey:@"myWalletArray"];

    [defaults synchronize];
    NSLog(@"I am saved");

我在 didSelectRowAtIndexPath 中调用此方法。当我运行应用程序,然后创建一个新的卡片实例时,单击表格单元格,这会出现在我的日志中。

2012-05-04 14:51:00.900 CardWallet[24998:f803] *** -[NSUserDefaults setObject:forKey:]: Attempt to insert non-property value '("<Card: 0x6aa02f0>")' of class '__NSArrayM'.  
Note that dictionaries and arrays in property lists must also contain only property values.

这可能是什么原因?你能建议我如何去做吗?

提前致谢。

【问题讨论】:

首先删除数组的属性,然后使用 nslog 检查数组中有哪些值作为键 【参考方案1】:

您的 Card 类还必须符合 NSCoding Protocol,因为您只能将 NSDataNSStringNSArrayNSDictionaryNSNumberNSUserDefaults 一起存储。 这意味着,您需要向您的类添加两个方法:

- (void)encodeWithCoder:(NSCoder *)enCoder 
    [super encodeWithCoder:enCoder];

    [enCoder encodeObject:instanceVariable forKey:INSTANCEVARIABLE_KEY];

    // Similarly for the other instance variables.
    ....


- (id)initWithCoder:(NSCoder *)aDecoder 

   if(self = [super initWithCoder:aDecoder]) 
       self.instanceVariable = [aDecoder decodeObjectForKey:INSTANCEVARIABLE_KEY];

       // similarly for other instance variables
       ....
   

   return self;

然后在将其存储到 NSUserDefaults 之前创建一个 NSData NSKeyedArchiver。 像这样:

 NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
 NSData *yourArrayAsData = [NSKeyedArchiver archivedDataWithRootObject:yourArray];
 [ud setObject:sharesAsData forKey:kA_KEY_FOR_USERDEFAULTS];

【讨论】:

这还不够,NSUserDefaults 不会自动为你编码。你需要自己做! 问题,在我的卡类上,我有 3 个实例变量:名称、引脚和点数。鉴于此,是否意味着我也应该解码和编码 3 次? 然后你需要有 3 次 encodeObject:forKey: 和 3 次 decodeObjectForKey; 是的。如果您的变量不是对象(可以是 int 或 float),则使用 encodeInt:forKey:decodeIntForKey: 好的。 Ahm 在[super encodeWithCoder:enCoder]; 行上显示“没有可见的@interface for 'NSObject' 声明选择器'encodeWithCoder'”我在Card.h - (void) encodeWithCoder:(NSCoder *)enCoder; - (id) initWithCOder: (NSCoder *)aDecoder; 中声明了这些方法@ 注意要走另一条路,它是[NSKeyedUnarchiver unarchiveObjectWithData:data]【参考方案2】:
@implementation Card

- (void)encodeWithCoder:(NSCoder *)enCoder 

    [super encodeWithCoder:enCoder];
    [enCoder encodeObject:self.name forKey:@"CardName"];
    [enCoder encodeInt:self.pin forKey:@"CardPin"];
    [enCoder encodeDouble:self.points forKey:@"CardPoints"];


- (id)initWithCoder:(NSCoder *)aDecoder 

   if(self = [super initWithCoder:aDecoder]) 
   
       self.name = [aDecoder decodeObjectForKey:@"CardName"];
       self.pin = [aDecoder decodeIntForKey:@"CardPin"];
       self.points = [aDecoder decodeDoubleForKey:@"CardPoints"];      
   
   return self;


@end

假设name是NSString类型,pin是NSInteger类型,Points是Double类型,你可以直接在你的项目中使用上面的代码。

【讨论】:

【参考方案3】:

如果数组self.myWallet 包含不是属性列表对象的对象,您需要在保存前自己将其编码为NSData,并在加载时解码。

查看question的答案。

【讨论】:

谢谢!我已经完成了同样的答案,我已经尝试过了,但在运行时仍然存在错误。我会尝试上面的其他建议,你也评论了:)

以上是关于使用 NSUserDefaults 保存 NSMutableArray 不起作用的主要内容,如果未能解决你的问题,请参考以下文章

在 Swift 中使用 NSUserDefaults 保存 NSMutableArray 返回 Nil

NSUserDefaults 自动加载和保存数据

iOS 7 如何使用 NSUserDefaults 保存 NSNumber?

使用 NSUserDefaults 杀死应用程序后保存的数据丢失

保存到 NSUserDefaults 的字典总是返回 nil

将UIColor保存到NSUserDefaults并从NSUserDefaults加载