Friday 9 November 2012

Key Value Observing iOS / KVO


You can observe changes across different objects/classes. I think the problem is in the options parameter of addObserver:forKeyPath:options:context:.
There are various options for the type of observing you want to do. The KVO Guide is a good starting point, but you probably want NSKeyValueObservingOptionNew, which I use in the example below.
First, "name" should be a public property in ClassB.
Second, you probably don't need to add the observer to "b" in viewWillAppear in ClassA, because you don't need to add it everytime the ClassA view is going to appear. You just need to add the observer once, when you create the ClassB view. Once you've added the observer, theobserveValueForKeyPath:ofObject:change:context: method will be executed in ClassA, so you can do the update to the ClassA UI from there. You shouldn't need to do anything every time ClassA is about to appear.
In Class A, you should probably create ClassB just before you are going to push ClassB onto the controller stack, presumably in the event handler for some action the user took. Immediately after you create ClassB, add the observer in ClassA with the correct NSKeyValueObservingOption value.
If you just want to be notified whenever the public property "name" in ClassB is changed, then try this:
ClassB
@interface ClassB : UIViewController {
}

@property (retain) NSString* name;

- (void) aMethodThatModifiesName:(NSString*)newName;

@end


@implementation ClassB 

@synthesize name;

- (void) aMethodThatModifiesName:(NSString*)newName {
    // do some stuff
    self.name = newName;
}

@end
ClassA
@interface ClassA : UIViewController {
}

@property (nonatomic, retain) IBOutlet UILabel* nameLabel;

- (IBAction) someEventHandler:(id)sender;

@end

@implementation ClassA

- (IBAction) someEventHandler:(id)sender {
    ClassB* b = [[ClassB alloc]init];
    [b addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew context:NULL];
    [self.navigationController pushViewController:b animated:YES];
    [b release];
}

- (void) observeValueForKeyPath:(NSString*)keyPath ofObject:(id)object change:(NSDictionary*)change context:(void*)context {
    if ([keyPath isEqual:@"name"]) {
        NSString* changedName = [change objectForKey:NSKeyValueChangeNewKey];
        // do something with the changedName - call a method or update the UI here
        self.nameLabel.text = changedName;
    }
}

@end

No comments:

Post a Comment