简体   繁体   中英

How to observe the property change if a particular obj using KVO?

I have a two controller namely aViewController and bViewController . I have a textField in bViewController (called txt1 ). I have declared like the following:

In bViewController.m :

- (void)viewDidLoad
{
    [self addObserver:self forKeyPath:@"txt1.text" options:NSKeyValueObservingOptionNew context:nil];
}

And in aViewController.m :

- (void)viewDidLoad
{      
    bViewController *obj = [[bViewController alloc] init];
    [obj addObserver:self forKeyPath:@"txt1.text" options:NSKeyValueObservingOptionNew context:NULL];

    [super viewDidLoad];
        // Do any additional setup after loading the view, typically from a nib.
}

-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
    /*
        NSLog(@"%@",keyPath);
        NSLog(@"%@",object);
        NSLog(@"%@",change);
      */
        NSLog(@"%s",__PRETTY_FUNCTION__);
        if ([keyPath isEqualToString:@"txt1.text"]) {
            NSLog(@"text1 content changed");
        }
    }

When i add some text in txt1(after tapping return key), I am getting the error like following:

Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '<bViewController: 0x9134560>: An -observeValueForKeyPath:ofObject:change:context: message was received but not handled.
Key path: txt1.text
Observed object: <bViewController: 0x9134560>
Change: {
    kind = 1;
    new = werwetw;
}
Context: 0x0'
*** First throw call stack:
(0x1c92012 0x10cfe7e 0x1c91deb 0xb85406 0xb2267d 0xb2233c 0xb09417 0xb22b24 0xad7d60 0xb21eb5 0xdd707 0xe4b02 0xedda1 0xdc645 0x121fb5 0x1220e1 0xdc4e6 0x2a0a 0xe4d2b 0xed9f8 0x1923cf 0x198f7f 0x198a8c 0x1979fe 0x1a1c72 0x24ddb 0x1227f5 0x1227f5 0x1227f5 0x1227f5 0x1227f5 0x1227f5 0x1227f5 0x1227f5 0x24e35 0x24806 0x24beb 0x16698 0x1beddf9 0x1bedad0 0x1c07bf5 0x1c07962 0x1c38bb6 0x1c37f44 0x1c37e1b 0x1bec7e3 0x1bec668 0x13ffc 0x1fa2 0x1ed5)
libc++abi.dylib: terminate called throwing an exception

Can anyone tell me where i went wrong.

A couple of observations:

  1. B's viewDidLoad is adding an observer for its own property. That's unnecessary.

  2. I also wonder if B has implemented observeValueForKeyPath . That's moot because of my prior point, but if you add an observer, you must implement observeValueForKeyPath . This strikes me as the likely source of your exception.

  3. A is creating a local instance of B, adding an observer, and if you're using ARC, you're then letting B fall out of scope, being released, and thus you have an observer for an object that no longer exists. Or if you're not using ARC, you won't have that problem, but you'll leak your copy of B.

    You say you're getting to B and changing the text, so I have to assume that in an attempt to simplify the code sample, you omitted the code that would prevent this problem from manifesting itself (eg the code that pushes/presents B), so perhaps this is not an issue. But the key point here is that before an item that has observers is released, make sure the observers are removed.

  4. Unrelated to your problem, but B's viewDidLoad isn't calling [super viewDidLoad] .

  5. You're showing us the creation of observers, but not the removing of the observers at the appropriate time.

  6. As general counsel, in MVC environments like iOS, wouldn't suggest adding observers to another view (ie the UITextField ). I'd have B update its model properties based upon changes in its view, and have A as an observer to that model property, not to anything in B's view hierarchy. This is especially important in iOS versions prior to 6.0, because if B subsequently invoked a third controller, C, and a low memory condition arose, B's view could be released (and you don't want observers on items that could be deallocated).

It strikes me that before we go further diagnosing your KVO, you should demonstrate how A is invoking B.

  • Is it a controller that A segues to? In that case you shouldn't add the observer until you do that.

  • Is B a child controller and is A a custom container? In that case you have to add the custom container calls (eg addChildController , etc.).

If you can articulate the logical flow between A and B, we can better help you. Or perhaps more complete code snippets would help. Perhaps also articulate the business problem you're trying to solve.

Having said all of that, if you're trying to pass data between view controllers, there are far more effective ways of doing that (eg delegate protocols). KVO probably isn't the right technology if you're trying to pass data from a view controller back to the controller that presented it.

I don't really get what you are asking but after looking at your code it seems as if you want to observe whether a user changes the text in the UITextField..

In your ViewController.h add the method

(IBAction)textFieldChanged:(id)sender;

In your storyboard or XIB you can connect this method with your UITextField, as Sent Event choose either Value Changed or Editing Changed (tbh I don't know atm).

In your ViewController.m implement said method

(IBAction)textFieldChanged:(id)sender {
    if (![sender isKindOfClass:[UITextField class]]) {
        return;
    }

    UITextField *field = sender;
    NSString *text = field.text;
    // Do something with the text or the field
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM