iPhone Key-Value Observer: observer not registering in UITableViewController
Hi Fellow iPhone Developers,
I am an experienced software engineer but new to the iPhone platform. I have successfully imple开发者_开发技巧mented sub-classed view controllers and can push and pop parent/child views on the view controller stack. However, I have struck trouble while trying to update a view controller when an object is edited in a child view controller. After much failed experimentation, I discovered the key-value observer API which looked like the perfect way to do this. I then registered an observer in my main/parent view controller, and in the observer I intend to reload the view. The idea is that when the object is edited in the child view controller, this will be fired. However, I think that the observer is not being registered, because I know that the value is being updated in the editing view controller (I can see it in the debugger), but the observing method is never being called.
Please help!
Code snippets follow below.
Object being observed. I believe that this is key-value compliant as the value is set when called with the setvalue message (see Child View Controller below).
X.h:
@interface X : NSObject <NSCoding> {
NSString *name;
...
@property (nonatomic, retain) NSString *name;
X.m:
@implementation X
@synthesize name;
...
Main View Controller.h:
@class X;
@interface XViewController : UITableViewController {
X *x;
...
Main View Controller.m:
@implementation XViewController
@synthesize x;
...
- (void)viewDidLoad {
...
[self.x addObserver:self
forKeyPath: @"name"
options: (NSKeyValueObservingOptionNew |
NSKeyValueObservingOptionOld)
context:nil];
[super viewDidLoad];
}
...
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context
{
if ([keyPath isEqual:@"name"]) {
NSLog(@"Found change to X");
[self.tableView reloadData];
}
[super observeValueForKeyPath:keyPath
ofObject:object
change:change
context:context];
}
Child View Controller.m: (this correctly sets the value in the object in the child view controller)
[self.x setValue:[[tempValues objectForKey:key] text] forKey:@"name"];
Did you check if you instantiated your x object in viewDidLoad() before calling addObserver:forKeyPath:options:context: ? Your x object must be already allocated/initialized.
A minor consideration. Since the context parameter is declared as (void *), you should pass NULL, not nil (a null object pointer which stands for id 0, while NULL stands for (void *) 0; they represent both the same thing, 0, but in Objective C you must distinguish among nil, NULL and Nil which represents a null class pointer).
While key value observing may work well in your application, using the notification center may be better for communicating between "major" view controllers. (A "major" view controller being the main controller for, say, an iPhone's full screen view.)
This ensures that both view controllers still exist when the communication happens. KVO is, it appears to me, designed to be used within a common context -- a single view controller or model.
Class X does appear to be KVC compliant. Though you do not show whether you declare an @property for it in your code. I'll assume that you do.
Why are you doing this:
[self.X setValue:[[tempValues objectForKey:key] text] forKey:@"name"];
in your child view controller rather than:
self.name = [[tempValues objectForKey:key] text];
(And did you really mean self.X above? self.X is not self.x.)
One other note: you do not need to call the superclass of your -[observeValueForKeyPath: ofObject:change:context:] method.
Andrew
精彩评论