PDA

View Full Version : NSUserDefaults - can't write color information




neil.b
Dec 4, 2008, 06:49 AM
I've been playing around with one of Erica Sadun's examples (the persistence stuff).

In her example, she stores off the position of 16 randomly created ImageViews (which works fine) by doing;

NSMutableArray *locations = [[NSMutableArray alloc] init];

for (DragView *dv in [contentView subviews])
{
[locations addObject:NSStringFromCGRect([dv rect])];
}

[[NSUserDefaults standardUserDefaults] setObject:locations forKey:@"locations"];
[[NSUserDefaults standardUserDefaults] synchronize];
[locations release];

I wanted to modify this so that I could also save off the background color of the image views, so I added this;

NSMutableArray *colors = [[NSMutableArray alloc] init];

then in the for{} loop;

[colors addObject:[dv backgroundColor]];

and then after the for{}loop;

[[NSUserDefaults standardUserDefaults] setObject:colors forKey:@"colors"];

Now the weird thing is, the "colors" array is populated correctly by the for{} loop but if I try to read the objects back;

colors = [[NSUserDefaults standardUserDefaults] objectForKey:@"colors"];

it comes out with garbage but reading the "locations" back;

locs = [[NSUserDefaults standardUserDefaults] objectForKey:@"locationss"];

works as expected.

I've tried all sorts of things;

casting the colors as strings
getting the CGColor from dv.backgroundColor (in the for {} loop)
casting the CGColor as a string
setting all the colors to constants (in the for{} loop) i.e. [colors addObject:[UIColor redColor]];

but nothing works. When the object is read back from the user defaults, it reads back the right number of objects (16 in this case) but they're all set to the same number.

Can anyone shed some light on it or suggest a simpler way to do what I'm trying to do? I've spent a whole day on it and I'm no closer to a solution. :(

Thanks



robbieduncan
Dec 4, 2008, 07:08 AM
You need a function similar to NSStringFromCGRect (and I assume the reverse function that transforms a string into a CGRect) for CGColor. Check the documents to see if there is one already there, if not you will have to write your own. Casting to a NSString is not going to work.

You need to read-up on the types that NSUserDefaults can store: it's a very small list...

neil.b
Dec 4, 2008, 09:04 AM
Thanks Robbie.

I've given up on this for a while.

You were right about the few types that UserDefaults will accept. You'd think there might be a warning or something.

There is no equivalent NSStringFromCGColor/CGColorFromNSString and I don't think I'm up to writing one just yet :)

robbieduncan
Dec 4, 2008, 09:06 AM
You were right about the few types that UserDefaults will accept. You'd think there might be a warning or something.

Well it does say "A defaultís value must be a property list, that is, an instance of (or for collections a combination of instances of): NSData, NSString, NSNumber, NSDate, NSArray, or NSDictionary. If you want to store any other type of object, you should typically archive it to create an instance of NSData. For more details, see User Defaults Programming Topics for Cocoa." in the documentation (http://developer.apple.com/DOCUMENTATION/Cocoa/Reference/Foundation/Classes/NSUserDefaults_Class/Reference/Reference.html) :p

neil.b
Dec 4, 2008, 10:03 AM
:p

I meant in terms of giving you a compile-time error. Xcode will quite happily let you try to write a, say, UIColor without batting an eyelid. From there I just assumed it was an acceptable object, not being told otherwise.

Yes, yes. Documentation. :)

robbieduncan
Dec 4, 2008, 10:11 AM
I meant in terms of giving you a compile-time error. Xcode will quite happily let you try to write a, say, UIColor without batting an eyelid. From there I just assumed it was an acceptable object, not being told otherwise.

Yep, that would be nice, but as the setObject:forKey: method has to support any of the object types that can actually be written it is typed as taking an object of type id, i.e. any object, so the compiler cannot actually issue the warning you want.

Of course Apple could fix this by creating a protocol for "property list objects", say called PropertyListObject and changing the declaration to be something like (I think this is valid):


- (void)setObject:(id<PropertyListObject>)value forKey:(NSString *)defaultName


And then update the definitions for the few classes that are acceptable to indicate they implement this protocol.

Of course I don't actually expect Apple to do this...

neil.b
Dec 4, 2008, 10:39 AM
Fair point :)

I've just realised where I recognise your name from. Car website (PH)?

I'm on there too, different username though. :)

robbieduncan
Dec 4, 2008, 10:40 AM
Fair point :)

I've just realised where I recognise your name from. Car website (PH)?

I'm on there too, different username though. :)

Yep, I've got an account there (same username as here), but I don't post all that much. Not like here :o