(Note: full project for experiments may be found here: https://github.com/snechaev/cocoa-validation-question)
I have a simple two-column view-based NSTableView connected to the data using the Cocoa bindings via the `ArrayController:
- File owner for the window is my
WindowController ArrayController'sContent Arrayis binded to the File owner's->Data
- The Value column content (which is
TextField) is binded to the Table Cell View ->objectValue.Value. The "Validates immediately" option is turned on.
The data model for the table is as follows
//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");
}
}
}
}
The model implements validation for the Value parameter values using the validateValue(_:forKey:) override. The validation works fine except for the following case:
- enter an invalid value, for example "456"
- click "OK" in the error message
- press Esc on the keyboard
The result is that the edited cell has lost the focus, but remains with the invalid value. In addition, when the user returns to edit mode for this cell and presses Enter, no error message is displayed. And the cell will still remains with the invalid value, so the user may think that this value is fully valid. If we inspect the data model we will clearly see that the invalid value was not assigned in the corresponding TestClass instance (which is ok).
So the question is how to handle such a situation so as not to mislead the user? It seems to me that the best way is to restore the initial value when Esc is pressed, but I can't find a way to do this. And maybe Apple's guidelines advise the other behavior for this situation?
It looks like a bug in the view based
NSTableView. The cell basedNSTableViewand aNSTextFieldoutside a table view do nothing when Esc is pressed and beep. Validating the data in a formatter has a similar issue.Workaround 1 in a
NSTextFieldsubclass:Workaround 2 in a
NSTableViewsubclass:The outline views in Finder and Xcode always discard the change if it's invalid. I don't know how to do this and I think it's more user-friendly to be able to fix a typo.