Andy Ibanez
Andy Ibanez

Reputation: 12254

KVO Not Triggering When Value Changes

I'm trying to do some tests with Apple's KVC but for some reason I can't get KVO to trigger when I change a value via KVC.

I have the following code:

#import <Foundation/Foundation.h>

@interface Character : NSObject
{
    NSString *characterName;
    NSInteger ownedClowCards;
}
@property (nonatomic, retain) NSString *characterName;
@property (nonatomic, assign) NSInteger ownedClowCards;
-(void)hasLostClowCard;
-(void)hasGainedClowCard;
@end

@implementation Character
@synthesize characterName;
@synthesize ownedClowCards;

-(void)hasLostClowCard
{

}

-(void)hasGainedClowCard
{

}

-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
    NSLog(@"Change");
}

@end

int main()
{
    Character *sakura;
    Character *shaoran;

    //---------------------------------------------------------------------
    // Here begins the KVO section.

    [sakura addObserver:sakura forKeyPath:@"ownedClowCards" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil];

    //Create and give the properties some values with KVC...

    sakura = [[Character alloc] init];
    [sakura setValue:@"Sakura Kinomoto" forKey:@"characterName"];
    [sakura setValue:[NSNumber numberWithInt:20] forKey:@"ownedClowCards"];

    shaoran = [[Character alloc] init];
    [shaoran setValue:@"Li Shaoran" forKey:@"characterName"];
    [shaoran setValue:[NSNumber numberWithInt:21] forKey:@"ownedClowCards"];

    //Done! Now we are going to fetch the values using KVC.

    NSString *mainCharacter = [sakura valueForKey:@"characterName"];
    NSNumber *mainCharCards = [sakura valueForKey:@"ownedClowCards"];

    NSString *rival = [shaoran valueForKey:@"characterName"];
    NSNumber *rivalCards = [shaoran valueForKey:@"ownedClowCards"];

    NSLog(@"%@ has %d Clow Cards", mainCharacter, [mainCharCards intValue]);
    NSLog(@"%@ has %d Clow Cards", rival, [rivalCards intValue]);

    [sakura setValue:[NSNumber numberWithInt:22] forKey:@"ownedClowCards"];
}

Like you can see it's really, really basic code, so I'm ashamed I can't get this to work for whatever reason. Everything I'm trying to do is to get a notification when ownedClowCards changes. I am registering the observers. When I run my program, I expect to see the message "Changed" once when the program is done running. But it never does. Changed is never printed to my program so I assume observeValueForKeyPath:ofObject:change:context: is not getting called.

Any help?

Upvotes: 3

Views: 4038

Answers (2)

Analog File
Analog File

Reputation: 5316

[sakura addObserver:sakura forKeyPath:@"ownedClowCards" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil];

You are doing the above before initializing sakura. Of course setting nil to observe changes to nil does nothing.

Upvotes: 4

DrummerB
DrummerB

Reputation: 40201

You add your observer to an object that doesn't exist yet.

Character *sakura;

This simply declares the variable, but doesn't actually allocate or initialize it yet.

Try calling sakura = [[Character alloc] init]; before you register as an observer.

And by the way NSString properties usually use the copy flag and not retain. And a memory management flag (assign) doesn't make sense in the case of a primitive type (NSInteger).

Upvotes: 3

Related Questions