37

I am trying to do simple KVO example, but I am having problems.

This is my *.m file:

#import "KVO_ViewController.h"

@interface KVO_ViewController ()

@property NSUInteger number;

@end

@implementation KVO_ViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.

    [self addObserver:self forKeyPath:@"number" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil];
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

- (IBAction)incNumber:(id)sender
{
    _number++;
    NSLog(@"%d", _number);
}

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

    if([keyPath isEqualToString:@"number"])
    {
        id oldC = [change objectForKey:NSKeyValueChangeOldKey];
        id newC = [change objectForKey:NSKeyValueChangeNewKey];

        NSLog(@"%@ %@", oldC, newC);
    }
}

@end

Note: I have a button which when clicked it will increment the number property.
I want to be notified when number property is changed.

The code is not working and I can not figure it why.

Shaun Bouckaert
  • 8,417
  • 1
  • 17
  • 20
WebOrCode
  • 6,852
  • 9
  • 43
  • 70

3 Answers3

28

KVO works with setter and getter and in incNumber you are directly accessing iVar so instead of that use self.number

- (IBAction)incNumber:(id)sender
{
    self.number++;
    NSLog(@"%d", self.number);
}
codester
  • 36,891
  • 10
  • 74
  • 72
  • 1
    `self.number++` is also working. In 10 minutes I will accept your answer. – WebOrCode Jul 26 '14 at 09:29
  • 2
    In all my reading about KVO, nobody has bothered to mention that you need to set properties this way until I found this. Thanks. – inorganik Nov 12 '14 at 17:22
  • you mean unlike custom `init` & `dealloc` methods where you **shouldn't** use self.property...here you actually **should** use `self.property`? – mfaani May 25 '16 at 00:53
10

Rather than:

_number++;

Try:

[self willChangeValueForKey:@"number"];
_number++;
[self didChangeValueForKey:@"number"];

or ever better just:

self.number++

And let the system take care of the willChangeValueForKey: and didChangeValueForKey: methods.

Abizern
  • 146,289
  • 39
  • 203
  • 257
  • 4
    what if the object is not in the same class. Its an object in a singleton class. How to apply KVO on that. – Nishant Oct 13 '14 at 16:15
2
@interface TraineeLocationCell : UIView
@property (strong, nonatomic) NSString *traineeAddress;
@end

@implementation

// in textview delgate method  i am setting traineeAddress string value
- (void)textViewDidEndEditing:(UITextView *)textView
{
    if (textView.text.length >0)
    [self setValue:textView.text forKey:@"traineeAddress"];

}

@end

and in other class where i am using this class

 TraineeLocationCell *locationView;//create object here
 [locationView addObserver:self forKeyPath:@"traineeAddress" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil];//observing the key in this class

//this is the delegate method which take care of value is changed or not

-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
   if([keyPath isEqualToString:@"traineeAddress"]){
        if (!settingsValues.address)
            settingsValues.address = [[NSMutableArray alloc]initWithObjects:[change valueForKey:@"new"], nil];

        else
            [settingsValues.address replaceObjectAtIndex:0 withObject:[change valueForKey:@"new"]];
    }
}
parvind
  • 877
  • 10
  • 22