Cocoa 向绑定的NSFormCell添加编辑行为

Cocoa 向绑定的NSFormCell添加编辑行为,cocoa,cocoa-bindings,key-value-observing,Cocoa,Cocoa Bindings,Key Value Observing,我有一个具有客户ID属性的核心数据模型类。它绑定到一个窗体单元格。当用户完成编辑文本时,我希望有机会使用依赖于新旧值的逻辑将其条目转换为大写 理想情况下,我希望使用一个可以在nib中实例化并连接到文本单元格的对象,使行为靠近它所属的视图。但我会接受一个我必须连接到模型上的对象 我用三种不同的方式实现了这一点: 模型类中的自定义setter方法 实现NSControlTextEditingDelegate的文本编辑委托 Helper类,它使用KVO来通知更改并启动后续更改 这三种实现都有问题。这些

我有一个具有客户ID属性的核心数据模型类。它绑定到一个窗体单元格。当用户完成编辑文本时,我希望有机会使用依赖于新旧值的逻辑将其条目转换为大写

理想情况下,我希望使用一个可以在nib中实例化并连接到文本单元格的对象,使行为靠近它所属的视图。但我会接受一个我必须连接到模型上的对象

我用三种不同的方式实现了这一点:

模型类中的自定义setter方法 实现NSControlTextEditingDelegate的文本编辑委托 Helper类,它使用KVO来通知更改并启动后续更改 这三种实现都有问题。这些问题分别是:

此行为不属于模型中。例如,我应该能够在代码中设置属性,而不触发它。 我无法获取before值,因为表单单元格未提供controlTextDidBeginEditing:调用,并且在调用controlTextDidEndEditing:时旧值已消失。此外,在不键入任何内容的情况下,在字段中进行制表符进出会触发对ControlTextDiEndEditing:的调用。 当观察触发用户的更改,并且我启动了对该属性的后续更改时,视图将忽略更改通知,并且不会重新绘制。我想装订工这样做是为了提高效率。通常在更新模型时,它可以忽略正在更新的字段中的KVO观测值。 您将如何解决此问题?

之后,听起来有一些可行的方法:

在模型类上放置一个类别并覆盖validateMyKey 亚类化NSFormCell 我两个都试过了。更多问题:

validateMyKey直到模型自身更新后才会调用,因此旧值不可用。 editWithFrame:inView:editor:delegate:event:在输入字段时并不总是被调用,因此很难访问endEditing:中的旧值。 新的解决方案是对我原来的2:text editing委托的改进,实现了NSControlTextEditingDelegate

与controlTextDidBeginEditing:和controlTextDidEndEditing:不同,只实现控件:TextShoulDediting:。在该方法中,如果需要,请操纵文本,然后返回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;
}