Question

I've encountered a weird bug and would like to check if I'm using my Key value observing of changes to NSUserDefaults correctly.

I have used this code in two places in my app without issues, then I added 3rd controller that observes values for "goldCount" and "energyCount". Now when I set the initial value, the app crashes with exc_bad_access. I'm adding this controller to the view 2 seconds after it's parent view appears using performSelectorAfterDelay.

Just before displaying the game screen, I set these properties:

//crash on this line 
[[NSUserDefaults standardUserDefaults] setInteger:200 forKey: goldCount]; 

[[NSUserDefaults standardUserDefaults] setInteger:150 forKey: energyCount];

Within 3 different view controllers, I have this code in viewDidLoad:

NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
[defaults addObserver:self
           forKeyPath:@"goldCount"
              options:NSKeyValueObservingOptionNew
              context:NULL];

[defaults addObserver:self
           forKeyPath:@"energyCount"
              options:NSKeyValueObservingOptionNew
              context:NULL];

self.goldLabel.text = [NSString stringWithFormat:@"%i",[[GameDataManager sharedInstance] currentGoldCount]];
self.energyLabel.text = [NSString stringWithFormat:@"%i",[[GameDataManager sharedInstance] currentEnergyCount]];

Here's how the class updates it's labels:

// KVO handler
-(void)observeValueForKeyPath:(NSString *)aKeyPath ofObject:(id)anObject
                       change:(NSDictionary *)aChange context:(void *)aContext
{

    //aKeyPath gives us the name of a user default that has changed
    if([aKeyPath isEqualToString:@"goldCount"])
    {
        //we are interested in the new value
        self.goldLabel.text = [NSString stringWithFormat:@"%i",[[aChange objectForKey:@"new"] intValue]];
    }else if([aKeyPath isEqualToString:@"energyCount"])
    {
        self.energyLabel.text = [NSString stringWithFormat:@"%i",[[aChange objectForKey:@"new"] intValue]];
    }

}

After adding a call to [[NSUserDefaults standardUserDefaults] synchronize]; I get this exception the second time around:

Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '( ): An -observeValueForKeyPath:ofObject:change:context: message was received but not handled. Key path: goldCount Observed object: Change: { kind = 1; new = 205; } Context: 0x0'

Was it helpful?

Solution

NSUserDefaults is not documented to be KVO compliant so it's not possible to observe defaults by their key. This might be the reason for the crash but without a stack trace it's not possible to tell.

There is a notification you can register for that announces changes to the defaults system: NSUserDefaultsDidChangeNotification.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top