1

我有一个两个控制器,即aViewControllerbViewController。我在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

谁能告诉我哪里出错了。

4

2 回答 2

1

几点观察:

  1. BviewDidLoad正在为其自己的财产添加一个观察者。那是不必要的。

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

  3. A 正在创建 B 的本地实例,添加一个观察者,如果你使用 ARC,那么你会让 B 超出范围,被释放,因此你有一个不再存在的对象的观察者。或者如果你不使用 ARC,你不会有这个问题,但你会泄露你的 B 副本。

    您说您要到达 B 并更改文本,所以我必须假设为了简化代码示例,您省略了会阻止此问题表现出来的代码(例如,推送/呈现 B 的代码) ,所以也许这不是问题。但这里的关键点是,在发布具有观察者的项目之前,请确保移除观察者。

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

  5. 您向我们展示了观察者的创建,而不是在适当的时间移除观察者。

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

让我感到震惊的是,在我们进一步诊断您的 KVO 之前,您应该演示 A 是如何调用 B 的。

  • 它是 A 所追求的控制器吗?在这种情况下,您不应该添加观察者,直到您这样做。

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

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

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

于 2013-04-18T14:15:54.123 回答
1

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

在你的 ViewController.h 添加方法

(IBAction)textFieldChanged:(id)sender;

在您的故事板或 XIB 中,您可以将此方法与您的 UITextField 连接,因为Sent Event选择V​​alue ChangedEditing Changed(我不知道 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
}
于 2013-04-18T19:00:18.277 回答