如何观察使用KVO的特定对象的属性变化



我有两个控制器,即aViewControllerbViewController。我有一个textField在bViewController(称为txt1)。我像这样声明:

在bViewController.m

:

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

在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");
        }
    }

当我在txt1中添加一些文本(点击返回键后),我得到的错误如下:

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

谁能告诉我我哪里出错了

几点观察:

  1. B的viewDidLoad正在为自己的属性添加一个观察者。这是不必要的。

  2. 我也想知道B是否已经实现了observeValueForKeyPath。由于我之前的观点,这是没有意义的,但如果您添加观察者,则必须实现observeValueForKeyPath。我觉得这很可能是你的异常的来源。

  3. A正在创建B的一个局部实例,添加一个观察者,如果你使用ARC,你就会让B脱离作用域,被释放,这样你就有了一个不再存在的对象的观察者。或者如果你不使用ARC,你不会有这个问题,但你会泄漏你的b副本。

    你说你要到B并改变文本,所以我不得不假设,在试图简化代码示例中,你省略了可以防止这个问题出现的代码(例如,推动/呈现B的代码),所以也许这不是一个问题。但这里的关键点是,在释放具有观察者的项之前,确保将观察者删除。

  4. 与你的问题无关,但B的viewDidLoad没有调用[super viewDidLoad]

  5. 您向我们展示了观察者的创建,但没有在适当的时候删除观察者。

  6. 作为总顾问,在MVC环境中,如iOS,不建议添加观察者到另一个视图(即UITextField)。我会让B根据其视图的变化更新其模型属性,并让A作为该模型属性的观察者,而不是B的视图层次结构中的任何东西。这在6.0之前的iOS版本中尤其重要,因为如果B随后调用了第三个控制器C,并且出现了低内存状况,B的视图可能会被释放(并且你不希望在可能被释放的项目上看到观察者)。

我突然想到,在我们进一步诊断您的KVO之前,您应该演示A如何调用b。

  • 是a segue到的控制器吗?在这种情况下,你不应该添加观察者,直到你这样做。

  • B是子控制器和a是自定义容器?在这种情况下,你必须添加自定义容器调用(例如addChildController等)。

如果你能清晰地表达A和B之间的逻辑流程,我们可以更好地帮助你。或者更完整的代码片段可能会有所帮助。也许还可以清楚地说明您正在尝试解决的业务问题。

说了这么多,如果你试图在视图控制器之间传递数据,有更有效的方法(例如委派协议)。如果你试图将数据从视图控制器传递回呈现它的控制器,KVO可能不是正确的技术。

我真的不明白你在问什么,但在看了你的代码之后,似乎你想观察用户是否改变了UITextField中的文本..

在ViewController.h中添加方法

(IBAction)textFieldChanged:(id)sender;

在你的故事板或XIB你可以连接这个方法与你的UITextField,作为发送事件选择值更改编辑更改 (tbh我不知道atm)。

在你的ViewController中。M实现上述方法

(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
}

最新更新