0

I have made a category for saving number of app runs like so,

static NSString * const AppRuns = @"IP_AppRuns";

@implementation NSUserDefaults (RegisteredUser)

+ (void)saveRuns:(NSNumber *)value
{
    [[NSUserDefaults standardUserDefaults] setObject:value forKey:AppRuns];
}

+ (NSNumber *)runs
{
    return [[NSUserDefaults standardUserDefaults] objectForKey:AppRuns];
}
....

And I'm setting it in my App delegate didFinishLaunchingWithOptions method.

[NSUserDefaults saveRuns: @(21)];
[[NSUserDefaults standardUserDefaults] synchronize];
NSLog(@"App has run %ld times", [[NSUserDefaults runs] integerValue]);

But, I get EXC_BAD_ACCESS, which makes me suspect that it isn't getting saved.

However, the following works:

[[NSUserDefaults standardUserDefaults] setObject:@(17) forKey:@"AppRuns"];
[[NSUserDefaults standardUserDefaults] synchronize];
NSLog(@"App has run %ld times", [[[NSUserDefaults standardUserDefaults] valueForKey:@"AppRuns"] integerValue]);

What am I doing wrong?

Zaxter
  • 2,939
  • 3
  • 31
  • 48
  • I tried the top one and it worked fine for me. – Will M. Jul 31 '15 at 18:12
  • Try setting an exception breakpoint to make sure you know where the exception is occuring, or posting a backtrace – Will M. Jul 31 '15 at 18:14
  • @WillM. Did you try by creating a category? And calling the method from `didFinishLaunchingWithOptions`? I will try setting a breakpoint. – Zaxter Jul 31 '15 at 18:18
  • Yup. I created a category for `NSUserDefaults`, copied your code into it, filled in the header, imported that header into `AppDelegate` and then copied your calling code into `didFinishLaunchingWithOptions`. Got this output `2015-07-31 14:11:57.674 TestStuff[52594:6855419] App has run 21 times` – Will M. Jul 31 '15 at 18:21
  • also note that you don't need to call synchronize so often http://stackoverflow.com/questions/9647931/nsuserdefaults-synchronize-method – Will M. Jul 31 '15 at 18:24
  • Thanks for confirming the category code isn't the problem @WillM.. I thought this was related to old keys as Klevison suggested and tried the removeObjectForKey, still no avail. I'm simply using the second method I wrote above. – Zaxter Jul 31 '15 at 18:42
  • Did you set the exception breakpoint to try to find the line it was crashing on? Do this by going to the breakpoint menu in the left menu (looks like a pentagon thing, second from the right), then click the plus at the bottom left of the screen, then "Add exception breakpoint" – Will M. Jul 31 '15 at 18:47

1 Answers1

0

+ (NSNumber *)runs uses objectForKey to access NSUserDefaults

Your second example uses valueForKey to access NSUserDefaults

valueForKey and objectForKey both will return the object for the given key. But here valuForKey is key-value coding (KVC).

If key does not start with “@”, invokes objectForKey:. If key does start with “@”, strips the “@” and invokes [super valueForKey:] with the rest of the key.

EDITED

Can you reinstall your app(clean old NSUserDefaults values) and try this code?

@implementation NSUserDefaults (RegisteredUser)

+ (void)saveRuns:
{
    NSNumber *runs = [[NSUserDefaults standardUserDefaults] objectForKey:AppRuns];
    [[NSUserDefaults standardUserDefaults] setObject:runs++ forKey:@"Runs"];
    [[NSUserDefaults standardUserDefaults] synchronize];
}

+ (NSNumber *)runs
{
    return [[NSUserDefaults standardUserDefaults] objectForKey:@"Runs"];
}
Klevison
  • 3,342
  • 2
  • 19
  • 32
  • I changed `objectForKey` in the category methods with `valueForKey`, but I still get the same problem. – Zaxter Jul 31 '15 at 18:17
  • Maybe you got problem with old values.. My answer was edited.. try it – Klevison Jul 31 '15 at 18:24
  • Still getting EXC_BAD_ACCESS. :( Thanks for your time. – Zaxter Jul 31 '15 at 18:40
  • 1) Check if existe value for `objectForKey`.. If not you cant sum this value (runs++).. 2) add an exception breakpoint and see the line error: http://stackoverflow.com/a/17802723/846780 – Klevison Jul 31 '15 at 18:56