title: How to store custom objects in NSUserDefaults
body: <p>Alright, so I've been doing some poking around, and I realize my problem, but I don't know how to fix it.  I have made a custom class to hold some data.  I make objects for this class, and I need to them to last between sessions.  Before I was putting all my information in <code>NSUserDefaults</code>, but this isn't working.</p>
  
  <pre><code>-[NSUserDefaults setObject:forKey:]: Attempt to insert non-property value '&lt;Player: 0x3b0cc90&gt;' of class 'Player'.
  </code></pre>
  
  <p>That is the error message I get when I put my custom class, "Player", in the <code>NSUserDefaults</code>.  Now, I've read up that apparently <code>NSUserDefaults</code> only stores some types of information.  So how an I get my objects into <code>NSUSerDefaults</code>?</p>
  
  <p>I read that there should be a way to to "encode" my custom object and then put it in, but I'm not sure how to implement it, help would be appreciated!  Thank you!</p>
  
  <p>****EDIT****</p>
  
  <p>Alright, so I worked with the code given below (Thank you!), but I'm still having some issues.  Basically, the code crashes now and I'm not sure why, because it doesn't give any errors.  Perhaps I'm missing something basic and I'm just too tired, but we'll see.  Here is the implementation of my Custom class, "Player":</p>
  
  <pre><code>@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
  </code></pre>
  
  <p>Implementation File:</p>
  
  <pre><code>#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
  </code></pre>
  
  <p>So that's my class, pretty straight forward, I know it works in making my objects.  So here is the relevant parts of the AppDelegate file (where I call the encryption and decrypt functions):</p>
  
  <pre><code>@class MainViewController;
  
  @interface MagicApp201AppDelegate : NSObject &lt;UIApplicationDelegate&gt; {
      UIWindow *window;
      MainViewController *mainViewController;
  }
  
  @property (nonatomic, retain) IBOutlet UIWindow *window;
  @property (nonatomic, retain) MainViewController *mainViewController;
  
  -(void)saveCustomObject:(Player *)obj;
  -(Player *)loadCustomObjectWithKey:(NSString*)key;
  
  
  @end
  </code></pre>
  
  <p>And then the important parts of the implementation file:</p>
  
  <pre><code>    #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;
  }
  </code></pre>
  
  <p>Eeee, sorry about all the code.  Just trying to help.  Basically, the app will launch and then crash immediatly.  I've narrowed it down to the encryption part of the app, that's where it crashes, so I'm doing something wrong but I'm not sure what.  Help would be appreciated again, thank you!</p>
  
  <p>(I haven't gotten around to decrypting yet, as I haven't gotten encrypting working yet.)</p>