Question

When a user adds a new managed object, it shows up in a table, which scrolls down to the new entry, and the name of the new object (a default value) goes into editing mode.

I need to check if the name of the new object is unique in the datastore, so I can't use a formatter for this. I think the perfect moment where I should validate this, is whenever the user tries to commit the entry's name value, using textShouldEndEditing:.

I subclassed NSTableView and overrid following methods, just to be able to check in the log if they get called.

- (BOOL)textShouldEndEditing:(NSText *)textObject {
    NSLog(@"textSHOULDendEditing fired in MyTableView");
    return [super textShouldEndEditing:textObject];
}
- (BOOL)control:(NSControl *)control textShouldEndEditing:(NSText *)fieldEditor {
    NSLog(@"control:textShouldEndEditing fired in MyTableView");
    return YES;
}
- (void)textDidEndEditing:(NSNotification *)aNotification {
    NSLog(@"textDIDEndEditing fired in MyTableView");
}

textDidEndEditing: gets called fine, but textShouldEndEditing: does not.

In the NSTableView Class Reference, under Text Delegate Methods, both methods textShouldEndEditing: and textDidEndEditing: are listed. Someone please explain why one gets called and the other doesn't.


I think the NSTableView acts as the delegate for an NSTextField that gets instantiated as a black box delegate for the NSTextFieldCell. So what is referred to as delegate methods in the NSTableView Class Reference, actually implement the text manipulating methods for the NSTextField object.

I tried to declare the NSTextFieldCell as an outlet in my NSTableView. I also tried to declare several protocols in the NSTableView.

#import <AppKit/AppKit.h>
#import <Cocoa/Cocoa.h>
@interface MyTableView : NSTableView <NSTextDelegate, NSTextFieldDelegate, NSControlTextEditingDelegate, NSTableViewDelegate, NSTableViewDataSource> {
}
@end

Don't laugh, I even tried to declare my table view as its own delegate :P

Was it helpful?

Solution 3

I overrid -(void)awakeFromInsert; in the (subclassed) managed object, to construct a unique default value for the name-property.

Also, I ended up not overriding the -(BOOL)textShouldEndEditing: method in the table view. Instead, I check if a newly entered name-property is unique in the (subclassed) managed object's -(BOOL)validate<Key>:error:.

Together, the above two strategies result in unique name-properties in all managed objects.

Maybe I could have forced the NSTextFieldCell to go into editing mode, resulting in -(BOOL)textShouldEndEditing: to get called every time.


Some remarks though:

It seems -(BOOL)textShouldEndEditing: returns NO when the -(BOOL)validate<Key>:error: returns NO.

Both -(BOOL)textShouldEndEditing: and -(BOOL)validate<Key>:error: methods are called only when the user actually makes changes to the property.

OTHER TIPS

After banging my head one entire day on this issue without finding any conclusive answer in Apple documentation, I decided to share the solution I've found in case somebody else struggles with the same problem.

According to the documentation, as the original poster mentioned, the methods control:textShouldBeginEditing and control:textShouldEndEditing of NSControlTextEditingDelegate should be called directly on the delegate:

This message is sent by the control directly to its delegate object.

Furthermore, a Technical Q&A was issued by Apple with the title Detecting the start and end edit sessions of a cell in NSTableView where it's clearly stated the following:

A: How do I detect start and end edit sessions of a cell in NSTableView?

In order to detect when a user is about to start and end an edit session of a cell in NSTableView, you need to be set as the delegate of that table and implement the following NSControl delegate methods:

- (BOOL)control:(NSControl *)control textShouldBeginEditing:(NSText *)fieldEditor;

- (BOOL)control:(NSControl *)control textShouldEndEditing:(NSText *)fieldEditor;

The table forwards the delegate message it is getting from the text view on to your delegate object using the control:textShouldEndEditing: method. This way your delegate can be informed of which control the text view field editor is acting on its behalf.

I found nothing in Apple's documentation stating anything different and if someone does, a documentation pointer would really be appreciated.

In fact, this appears to be true if a cell-based NSTableView is being used. But as soon as you change the table to a view-based table, the delegate method is not called any longer on the table delegate object.

A Solution

However, some heuristic tests I performed showed that those delegate methods get called on a view-based table delegate if (and as far as I know: and only if):

  • The table delegate is set.
  • The delegate of the editable control is set.

If you remove either delegate, the methods of the NSControlTextEditingDelegate protocol will not be called.

What's unexpected according to the (only) documentation is setting the delegate of the editable control. On the other hand setting the delegate object to receive delegate notifications sounds rather intuitive to me, and that's why I tried in the first place. But there's a catch! The curious thing, though, is that that's not sufficient. If the table delegate is removed, the NSControlTextEditingDelegate methods will not be called even if the delegate of the editable control is set (which is the weirdest thing to me).

Hope this helps somebody else not to lose time on this issue.

in your question you mention the insertion of a "managed object" and that was the problem. It seems that you are using a view based table, but the textShouldEndEditing: method only gets called for cell based tables.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top