将编辑行为添加到绑定的NSFormCell

时间:2011-12-05 17:47:26

标签: cocoa cocoa-bindings key-value-observing

我有一个具有客户ID属性的Core Data模型类。它与形式单元格绑定在一起。当用户完成对文本的编辑时,我希望有机会将其条目转换为大写,使用依赖于旧值和新值的逻辑

理想情况下,我希望将行为保持在它所属的视图附近,使用可以在nib中实例化的对象并连接到文本单元格。但是我会选择一个与模型挂钩的对象。

我已经实现了以下三种不同的方式:

  1. 模型类中的自定义setter方法
  2. 文本编辑委托实施NSControlTextEditingDelegate
  3. 使用KVO注意更改并启动后续更改的帮助程序类
  4. 所有三个实现都有问题。问题分别为:

    1. 此行为不属于模型。我应该能够在代码中设置属性,例如,不触发它。
    2. 我无法获得“之前”值,因为表单单元格不提供controlTextDidBeginEditing:调用(并且在调用controlTextDidEndEditing:时旧值已消失)。此外,在不输入任何内容的情况下进出字段的标签会触发对controlTextDidEndEditing:的调用。
    3. 当观察触发用户的更改,并且我启动对该属性的后续更改时,视图将忽略更改通知,并且不会重绘。 (我认为绑定器是为了提高效率。通常在更新模型时,它可以忽略来自正在更新的字段的KVO观察结果。)
    4. 你会如何解决这个问题?

1 个答案:

答案 0 :(得分:0)

some discussion here之后,听起来像是一些可行的方法:

  1. 在模型类上添加一个类别并覆盖validateMyKey
  2. 子类化NSFormCell
  3. 我试过了两个。更多问题:

    1. 在模型更新之后才会调用validateMyKey,因此旧值不可用。
    2. 输入字段时并不总是调用
    3. editWithFrame:inView:editor:delegate:event:,因此很难在endEditing:中访问旧值。
    4. 新解决方案是对我原来的#2:文本编辑委托实施NSControlTextEditingDelegate的改进。

      而不是controlTextDidBeginEditing:controlTextDidEndEditing:,只执行control:textShouldEndEditing:。在该方法中,如有必要,操纵文本,然后返回YES。

      我在nib中实例化它并使其成为表单的委托(而不是单元格)。在下面的代码中,我使用infoForBinding:获取旧值,但如果您不使用绑定,则可以向模型对象添加插座。

      -(BOOL)control:(NSControl *)control textShouldEndEditing:(NSText *)fieldEditor {
          NSCell *cell = [(NSForm *)control selectedCell];
          NSString *identifier = [(NSCell *)[(NSForm *)control selectedCell] identifier];
          if (!identifier) return YES;
      
          NSDictionary *bindingInfo = [cell infoForBinding:@"value"];
          if (!bindingInfo) return YES;
          NSString *oldValue = [[bindingInfo valueForKey:NSObservedObjectKey] valueForKeyPath:[bindingInfo valueForKey:NSObservedKeyPathKey]];
      
          NSString *newValue = cell.stringValue;
      
          if ([identifier isEqualTo:@"firstField"]) {
              if (criteria)
                  cell.stringValue = ....;
      
          } else if ([identifier isEqualTo:@"secondField"]) {
              if (criteria)
                  cell.stringValue = ....;
          }
      
          return YES;
      }