(注意:完整的实验项目可以在这里找到: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:)
参数值的验证。除以下情况外,验证工作正常:
结果是编辑的单元格失去焦点,但仍保留无效值。此外,当用户返回到该单元格的编辑模式并按 Enter 键时,不会显示任何错误消息。并且该单元格仍将保留无效值,因此用户可能认为该值完全有效。如果我们检查数据模型,我们将清楚地看到相应的 TestClass 实例中没有分配无效值(这是可以的)。
那么问题是如何处理这样的情况才不会误导用户呢?在我看来,最好的方法是在按下 Esc 时恢复初始值,但我找不到方法来做到这一点。也许苹果的指南建议了这种情况下的其他行为?
它看起来像是基于视图的错误
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 中的大纲视图始终会放弃更改。我不知道该怎么做,我认为能够修复拼写错误对用户来说更加友好。