10

Currently I'm trying to save an NSRect to my user defaults. Right now I'm using a NSValue to wrap it as an object then save it into the user defaults as an object with the following code

[userDefaults setObject:[NSValue valueWithRect:rect forKey:@"Key"]];

However, when I run it, I get an error that says [NSUserDefaults setObject:forKey:]: Attempt to insert non-property value 'NSRect: {{0, 0}, {50, 50}}' of class 'NSConcreteValue'.

Does anyone know how I can fix this? Thanks.

TheAmateurProgrammer
  • 9,252
  • 8
  • 52
  • 71
  • 1
    Your missing a `]` in your example. – Joe Oct 11 '11 at 13:39
  • 1
    Missing brackets have nothing to do with this problem, your answer is on another SO thread which I'm linking. You will have to take additional steps to save your NSRect objects, I'm afraid - http://stackoverflow.com/questions/471830/why-nsuserdefaults-failed-to-save-nsmutabledictionary-in-iphone-sdk. – Perception Oct 11 '11 at 13:49
  • Thanks for the link. I totally forgot about how NSUserDefaults only support a certain amount of objects. – TheAmateurProgrammer Oct 11 '11 at 13:54

2 Answers2

55

Here is a much simpler solution, using NSString:

// store:
[[NSUserDefaults standardUserDefaults] 
   setValue:NSStringFromCGRect(frame) forKey:@"frame"];

// retrieve:
CGRect frame = CGRectFromString(
   [[NSUserDefaults standardUserDefaults] stringForKey:@"frame"]);

Swift 4

// store
UserDefaults.standard.set(NSStringFromCGRect(rect), forKey: "frame")

// retrieve
if let s = UserDefaults.standard.string(forKey: "frame") {
   let frame = CGRectFromString(s)
}
Mundi
  • 79,884
  • 17
  • 117
  • 140
  • 4
    +1 I do like simple, OP just needs to use `NSStringFromRect` and `NSRectFromString`. – Joe Oct 11 '11 at 14:14
14

NSValue is not supported by the user defaults.

The value parameter can be only property list objects: NSData, NSString, NSNumber, NSDate, NSArray, or NSDictionary. For NSArray and NSDictionary objects, their contents must be property list objects.

You need to archive the value into data then unarchive it when you access it.

NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
NSRect rect = { 0, 0, 10, 20 };
NSValue *value = [NSValue valueWithRect:rect];

NSData *data = [NSKeyedArchiver archivedDataWithRootObject:value];
[userDefaults setObject:data forKey:@"key"];
[userDefaults synchronize];

data = [userDefaults objectForKey:@"key"];
NSValue *unarchived = [NSKeyedUnarchiver unarchiveObjectWithData:data];
NSLog(@"%@", unarchived);
Joe
  • 56,979
  • 9
  • 128
  • 135