xcode 使用 NSUserDefaults 保存 NSMutableArray 不起作用

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10444131/
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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-15 00:11:26  来源:igfitidea点击:

Saving a NSMutableArray using NSUserDefaults not working

iphoneiosxcodensuserdefaults

提问by Grauzten

I have this mutable array named myWallet with its property declaration:

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

@property (nonatomic, strong) NSMutableArray *myWallet;

This array is being filled up by Cards, which is an object. I create a new instance of a Card from another View Controller so I use a delegate method in able to pass this created card on my initial View Controller which is a Table View Controller. Below is the delegate method

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

- (void)addCardViewController:(AddCardViewController *)sender didCreateCard:(Card *)newCard
{
    // insert a new card

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

    [self.tableView reloadData];
}

So far, I can create new instances of Card, and when I do, a new table cell appears in my initial view controller (Card Wallet VC).

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

What I want is when the user is done using the app, the created instance(s) of Card he / she previously created still appears on next run time of the app. So I used NSUserDefaults to do this. The method below is how I'm using NSUserDefaults to save.

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

- (void)saveMyWallet
{

    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];

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

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

I call this method inside the didSelectRowAtIndexPath. When I run the app, then create a new instance of a Card, click the table cell, this appears on my log.

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

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.

What could be a possible reason to this? And can you suggest me ways I can go about it.

这可能是什么原因?你能不能给我建议我可以做的事情。

Thanks in advance.

提前致谢。

回答by Jonas Schnelli

Your Card class must also conform to the NSCoding Protocolbecause you can only store NSData, NSString, NSArray, NSDictionaryand NSNumberwith NSUserDefaults. That means, you need to add two methods to your class:

你的卡类也必须符合NSCoding协议,因为你只能存储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;
}

Then create a NSData NSKeyedArchiver before storing it to NSUserDefaults. Like this:

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

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

回答by Janak Nirmal

@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

Assumed that name is of type NSString, pin is of type NSInteger and Points is of type Double you can use above code directly in your project.

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

回答by unexpectedvalue

If the array self.myWalletcontains objects that aren't property list objects you will need to encode it yourself to NSDatabefore saving, and decode when loading.

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

Check out the answer to that question.

查看该问题的答案。