views:

185

answers:

1

If I have a custom class Person which has three variables (which are propertized and synthesized):

NSString* theName;
float* theHeight;
int theAge;

Person instances are stored in an NSArray 'Group'. There is only one Group. What is the best way of storing and loading the Group in NSUserDefaults? (bearing in mind that float and int are not legal for NSUserDefaults)

+3  A: 

Write yer class like this:

@interface Person: NSObject <NSCoding> {
  NSString *name;
  float *height;    //Note height is a pointer, presumabaly due to a dependancy in code we dont control
  NSUInteger age;
}

@property (nonatomic, retain) NSString *name;
@property (readwrite) height;
@property (readwrite) age;

@end

@implementation Person

@synthesize name;
@synthesize height;
@synthesize age;

#define PersonNameKey @"PersonNameKey"
#define PersonHeightKey @"PersonHeightKey"
#define PersonAgeKey @"PersonAgeKey"

- (id)initWithCoder:(NSCoder *)decoder {
    self = [super init];
    if(self) {
        self.name = [decoder decodeObjectForKey:PersonNameKey];
            //height is a pointer to we need to do this
            &self.height = [decoder decodeFloatForKey:PersonHeightKey];
        self.age = [decoder decodeIntForKey:PersonAgeKey];
    }
    return self;
}

- (void)encodeWithCoder:(NSCoder *)encoder {
    [encoder encodeObject:self.name forKey:PersonNameKey];
    //dereferance the pointer to persist the value
    [encoder encodeFloat:*self.height forKey:PersonHeightKey]
    [encoder encodeInt:self.age forKey:PersonAgeKey];
}

- (void)dealloc {
    self.name = nil;
    [super dealloc];
}
@end

Then you can do a:

Person = [Person alloc] init];
person.name = @"name";
person.age = 10;
person.height = 1.6;
[NSUserDefaults standardUSerDefaults] setObject:person forKey:@"SomeKey"];

Person *newPerson = [[NSUserDefaults standardUSerDefaults] objectForKey:@"SomeKey"];

If you wanted to persist a collection of the objects you are in luck because NSArray is NSCoding Compliant. All you need to do is:

NSArray *arrayOfPersons = [person1, person2, person3, nil];
[NSUSerDefaults standardUSerDefaults] setObject:arrayOfPersons forKey@"SomeKey"];

Note: Ususaly before posting on SO I dbl check my code in a complier, but I'm reinstalling today so there may be typos.

Brad Smith
You have an extra retain in initWithCoder??
progrmr
+1 for detailed answer. If possible I'd prefer `NSString * const` to `#define` since I don't like using `#define` unless absolutely necessary (I've read enough Meyers).
Shaggy Frog
Thanks for your help. I'm not clear how it saves a Group (which can be of any number of Person's)..?
cannyboy
also, is it OK if I keep the variables as float* and int, since other parts of the class depend on those variable types..?
cannyboy
@progrmr thanks - I'm at WWDC today and was writing this while listing to a talk (edited) Wasn't really paying attention
Brad Smith
@cannyboy I actually didn't notice that you had your float declared as a pointer. That is strange to me in a Model class - but if you need to do it that way, you could persist the value of the float pointer, by using pointer syntax. I'll update the answer right now
Brad Smith
@Shaggy Frog, I've gone back and forth on that one, but I'm starting to agree with you
Brad Smith
(I mean replacing the ampersand with an asterisk, not removing it)
cannyboy