ios - 如何在 NSUserDefaults 中存储自定义对象

好的,所以我一直在四处寻找,我意识到我的问题,但我不知道如何解决它。我制作了一个自定义类来保存一些数据。我为这个类制作对象,我需要它们在 session 之间持续存在。在我将所有信息放入 NSUserDefaults 之前,但这不起作用。

-[NSUserDefaults setObject:forKey:]: Attempt to insert non-property value '<Player: 0x3b0cc90>' of class 'Player'.

这是我将自定义类“Player”放入 NSUserDefaults 时收到的错误消息。现在,我读到显然 NSUserDefaults 只存储某些类型的信息。那么如何将我的对象放入 NSUSerDefaults

我读到应该有一种方法可以“编码”我的自定义对象,然后将其放入,但我不确定如何实现它,不胜感激!谢谢!

****编辑****

好的,所以我使用了下面给出的代码(谢谢!),但我仍然遇到了一些问题。基本上,代码现在崩溃了,我不知道为什么,因为它没有给出任何错误。也许我错过了一些基本的东西,我太累了,但我们会看到的。这是我的自定义类“Player”的实现:

@interface Player : NSObject {
    NSString *name;
    NSNumber *life;
    //Log of player's life
}
//Getting functions, return the info
- (NSString *)name;
- (int)life;


- (id)init;

//These are the setters
- (void)setName:(NSString *)input; //string
- (void)setLife:(NSNumber *)input; //number    

@end

实现文件:

#import "Player.h"
@implementation Player
- (id)init {
    if (self = [super init]) {
        [self setName:@"Player Name"];
        [self setLife:[NSNumber numberWithInt:20]];
        [self setPsnCounters:[NSNumber numberWithInt:0]];
    }
    return self;
}

- (NSString *)name {return name;}
- (int)life {return [life intValue];}
- (void)setName:(NSString *)input {
    [input retain];
    if (name != nil) {
        [name release];
    }
    name = input;
}
- (void)setLife:(NSNumber *)input {
    [input retain];
    if (life != nil) {
        [life release];
    }
    life = input;
}
/* This code has been added to support encoding and decoding my objecst */

-(void)encodeWithCoder:(NSCoder *)encoder
{
    //Encode the properties of the object
    [encoder encodeObject:self.name forKey:@"name"];
    [encoder encodeObject:self.life forKey:@"life"];
}

-(id)initWithCoder:(NSCoder *)decoder
{
    self = [super init];
    if ( self != nil )
    {
        //decode the properties
        self.name = [decoder decodeObjectForKey:@"name"];
        self.life = [decoder decodeObjectForKey:@"life"];
    }
    return self;
}
-(void)dealloc {
    [name release];
    [life release];
    [super dealloc];
}
@end

这就是我的类(class),非常直接,我知道它可以用于制作我的对象。所以这里是 AppDelegate 文件的相关部分(我称之为加密和解密函数):

@class MainViewController;

@interface MagicApp201AppDelegate : NSObject <UIApplicationDelegate> {
    UIWindow *window;
    MainViewController *mainViewController;
}

@property (nonatomic, retain) IBOutlet UIWindow *window;
@property (nonatomic, retain) MainViewController *mainViewController;

-(void)saveCustomObject:(Player *)obj;
-(Player *)loadCustomObjectWithKey:(NSString*)key;


@end

然后是实现文件的重要部分:

    #import "MagicApp201AppDelegate.h"
    #import "MainViewController.h"
    #import "Player.h"

    @implementation MagicApp201AppDelegate


    @synthesize window;
    @synthesize mainViewController;


    - (void)applicationDidFinishLaunching:(UIApplication *)application {
    NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
        //First check to see if some things exist
        int startup = [prefs integerForKey:@"appHasLaunched"];
        if (startup == nil) {
//Make the single player 
        Player *singlePlayer = [[Player alloc] init];
        NSLog([[NSString alloc] initWithFormat:@"%@\n%d\n%d",[singlePlayer name], [singlePlayer life], [singlePlayer psnCounters]]); //  test
        //Encode the single player so it can be stored in UserDefaults
        id test = [MagicApp201AppDelegate new];
        [test saveCustomObject:singlePlayer];
        [test release];
}
[prefs synchronize];
}

-(void)saveCustomObject:(Player *)object
{ 
    NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
    NSData *myEncodedObject = [NSKeyedArchiver archivedDataWithRootObject:object];
    [prefs setObject:myEncodedObject forKey:@"testing"];
}

-(Player *)loadCustomObjectWithKey:(NSString*)key
{
    NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
    NSData *myEncodedObject = [prefs objectForKey:key ];
    Player *obj = (Player *)[NSKeyedUnarchiver unarchiveObjectWithData: myEncodedObject];
    return obj;
}

Eeee,对不起所有的代码。只是想帮忙。基本上,该应用程序将启动,然后立即崩溃。我已将其范围缩小到应用程序的加密部分,这就是它崩溃的地方,所以我做错了,但我不确定是什么。再次感谢您的帮助,谢谢!

(我还没有开始解密,因为我还没有开始加密工作。)

最佳答案

在您的 Player 类上,实现以下两种方法(将 encodeObject 调用替换为与您自己的对象相关的内容):

- (void)encodeWithCoder:(NSCoder *)encoder {
    //Encode properties, other class variables, etc
    [encoder encodeObject:self.question forKey:@"question"];
    [encoder encodeObject:self.categoryName forKey:@"category"];
    [encoder encodeObject:self.subCategoryName forKey:@"subcategory"];
}

- (id)initWithCoder:(NSCoder *)decoder {
    if((self = [super init])) {
        //decode properties, other class vars
        self.question = [decoder decodeObjectForKey:@"question"];
        self.categoryName = [decoder decodeObjectForKey:@"category"];
        self.subCategoryName = [decoder decodeObjectForKey:@"subcategory"];
    }
    return self;
}

NSUserDefaults读写:

- (void)saveCustomObject:(MyObject *)object key:(NSString *)key {
    NSData *encodedObject = [NSKeyedArchiver archivedDataWithRootObject:object];
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    [defaults setObject:encodedObject forKey:key];
    [defaults synchronize];

}

- (MyObject *)loadCustomObjectWithKey:(NSString *)key {
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    NSData *encodedObject = [defaults objectForKey:key];
    MyObject *object = [NSKeyedUnarchiver unarchiveObjectWithData:encodedObject];
    return object;
}

代码厚颜无耻地借自:saving class in nsuserdefaults

https://stackoverflow.com/questions/2315948/

相关文章:

ios - 总是将 self 的弱引用传递到 ARC 中的 block 中?

objective-c - 问号和冒号是什么意思(?: ternary operator) mean

objective-c - 覆盖 isEqual : and hash 的最佳实践

objective-c - 将 NSDate 转换为 NSString

ios - 如何以编程方式确定我的应用程序是否在 iphone 模拟器中运行?

ios - 不能在 Objective-C 中使用 Swift 类

ios - 为什么当应用程序从后台返回时不会调用 viewWillAppear?

ios - 如何强制 NSLocalizedString 使用特定语言

objective-c - 如何将 Swift 代码导入到 Objective-C?

objective-c - 对于 Objective-C 中用于访问 NSMutable 字典的每个