在 validateValue(_:forKey:) 失败后,NSTableView 单元格值可能仍为无效值。如何预防这种情况?

问题描述 投票:0回答:1

(注意:完整的实验项目可以在这里找到:https://github.com/snechaev/cocoa-validation-question

我有一个简单的基于两列视图的

NSTableView
,通过 `ArrayController:

使用 Cocoa 绑定连接到数据
  • 窗口的文件所有者是我的
    WindowController
  • ArrayController
    Content Array
    绑定到文件所有者的->
    Data
  • 值列内容(即
    TextField
    )绑定到表格单元格视图 ->
    objectValue.Value
    。 “立即验证”选项已打开。

该表的数据模型如下

//Data is a property of WindowController
@objc let Data : NSMutableArray = NSMutableArray(array: [TestClass(Name: "1"),
                                                         TestClass(Name: "2"),
                                                         TestClass(Name: "3"),
                                                         TestClass(Name: "4"),
                                                         TestClass(Name: "5")])


class TestClass: NSObject {
    @objc let Name : String!
    @objc var Value : String?
    
    init(Name: String!) {
        self.Name = Name
        self.Value = Name
    }
    
    override func validateValue(_ ioValue: AutoreleasingUnsafeMutablePointer<AnyObject?>, 
                                  forKey inKey: String) throws {
        if(inKey == #keyPath(Value)){
            guard let strVal = ioValue.pointee as? String 
            else {throw MyError.error("Value should be a string")}

            if(!strVal.starts(with: "1")){
                throw MyError.error("Value should starts with 1");
            }
        } 
    }
}

模型使用

Value
覆盖实现对
validateValue(_:forKey:)
参数值的验证。除以下情况外,验证工作正常:

  • 输入无效值,例如“456”
  • 在错误消息中单击“确定”
  • 按键盘上的 Esc

结果是编辑的单元格失去焦点,但仍保留无效值。此外,当用户返回到该单元格的编辑模式并按 Enter 键时,不会显示任何错误消息。并且该单元格仍将保留无效值,因此用户可能认为该值完全有效。如果我们检查数据模型,我们将清楚地看到相应的 TestClass 实例中没有分配无效值(这是可以的)。

那么问题是如何处理这样的情况才不会误导用户呢?在我看来,最好的方法是在按下 Esc 时恢复初始值,但我找不到方法来做到这一点。也许苹果的指南建议了这种情况下的其他行为?

swift validation nstableview cocoa-bindings
1个回答
0
投票

它看起来像是基于视图的错误

NSTableView
。当按下 Esc 并发出蜂鸣声时,基于单元格的
NSTableView
和表格视图外部的
NSTextField
不执行任何操作。在格式化程序中验证数据也有类似的问题。

NSTextField

子类中的解决方法 1:

class TextField: NSTextField { override func abortEditing() -> Bool { // bugfix, the data isn't restored after an error let aborted = super.abortEditing() // restore the data if aborted, let bindingInfo = infoForBinding(.value), let object = bindingInfo[.observedObject] as? NSObject, let keyPath = bindingInfo[.observedKeyPath] as? String { objectValue = object.value(forKeyPath: keyPath) } return aborted } }
NSTableView

子类中的解决方法 2:

class TableView: NSTableView {

    override func cancelOperation(_ sender: Any?) {
        // bugfix, the data isn't restored after an error
        
        // get the edited control
        var control: NSControl?
        if let firstResponder = window?.firstResponder {
            if let fieldEditor = firstResponder as? NSTextView,
                let delegate = fieldEditor.delegate as? NSControl {
                control = delegate
            }
            else if let firstResponder = firstResponder as? NSControl {
                control = firstResponder
            }
        }
        
        super.cancelOperation(sender)
        
        // restore the data
        if let control = control,
            let bindingInfo = control.infoForBinding(.value),
            let object = bindingInfo[.observedObject] as? NSObject,
            let keyPath = bindingInfo[.observedKeyPath] as? String {
            control.objectValue = object.value(forKeyPath: keyPath)
        }
    }
    
}

也许苹果的指南建议了这种情况下的其他行为?

如果更改无效,Finder 和 Xcode 中的大纲视图始终会放弃更改。我不知道该怎么做,我认为能够修复拼写错误对用户来说更加友好。

© www.soinside.com 2019 - 2024. All rights reserved.