textShouldEndEditing не вызывается в NSTableView

Когда пользователь добавляет новый управляемый объект, он отображается в таблице, которая прокручивается до новой записи, а имя нового объекта (значение по умолчанию) переходит в режим редактирования.

Мне нужно проверить, уникально ли имя нового объекта в хранилище данных, поэтому я не могу использовать для этого средство форматирования. Я думаю, что идеальный момент, когда я должен проверить это, — это всякий раз, когда пользователь пытается зафиксировать значение имени записи, используя textShouldEndEditing:.

Я создал подкласс NSTableView и переопределил следующие методы, просто чтобы иметь возможность проверять в журнале, вызываются ли они.

- (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: вызывается нормально, а textShouldEndEditing: нет.

В Справочнике по классу NSTableView в разделе Text Delegate Methods перечислены оба метода textShouldEndEditing: и textDidEndEditing:. Кто-нибудь, объясните, почему одному звонят, а другому нет.


Я думаю, что NSTableView действует как делегат для NSTextField, который создается как делегат черный ящик для NSTextFieldCell. Итак, что называется методами делегата в Справочник по классу NSTableView фактически реализуют методы управления текстом для объекта NSTextField.

Я попытался объявить NSTextFieldCell выходом в моем NSTableView. Я также пытался объявить несколько протоколов в файле NSTableView.

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

Не смейтесь, я даже пытался объявить свое табличное представление отдельным делегатом: P


person Fnord23    schedule 03.04.2012    source источник
comment
Разве это не протокол <NSTextDelegate>, который нужно реализовать? Кто-нибудь знает, как пересылаются NSTextDelegate методы NSTextFieldCell? Есть ли какая-либо документация вокруг? (Поверьте мне, я смотрел) Или есть объект выше по цепочке команд, который по умолчанию функционирует как NSTextDelegate (например, NSTableView)? Возможно ли, что некоторые методы NSTextDelegate переопределяются другим классом, который находится первым в цепочке команд?   -  person Fnord23    schedule 03.04.2012
comment
Нашел интересный документ в библиотеках разработчиков Mac OS X: Руководство по архитектуре текста Cocoa с множеством ссылок на другие технологии и примеры. Я вернусь, когда узнаю больше :)   -  person Fnord23    schedule 03.04.2012
comment
Отн. ="nofollow noreferrer">Редактирование текста в Руководстве по архитектуре текста Cocoa гласит: Уведомления об изменении текста и делегированные сообщения Сообщения textShouldBeginEditing: и textDidBeginEditing: отправляются только один раз в течение сеанс редактирования. Точнее, они отправляются при первом вводе пользователем, так как NSTextView стал первым ответчиком. Тот факт, что текст был выбран, не уведомлял текстовое поле о том, что выполняется редактирование.   -  person Fnord23    schedule 05.04.2012
comment
Представление может быть не лучшим местом для проверки ввода пользователя. Когда пользователь добавляет новый управляемый объект, нажимая кнопку «Добавить», на контроллер массива отправляется сообщение -(IBAction)add:(id)sender, которое, в свою очередь, использует описание объекта для вставки нового управляемого объекта в контекст управляемого объекта. Поэтому, когда пользователь фактически получает возможность редактировать свойство имени нового управляемого объекта, по крайней мере, некоторая проверка уже должна была произойти. Когда (необязательное) свойство имени не имеет значения по умолчанию (в IB), я хотел бы убедиться, что свойство имени не осталось пустым.   -  person Fnord23    schedule 16.04.2012
comment
Забавно, что когда пользователь нажимает кнопку "Добавить" и нажимает "Ввод" без внесения каких-либо изменений, метод -(BOOL)validate<Key>:error: подкласса управляемого объекта не вызывается. С другой стороны, проверка вызывается, когда пользователь активно редактирует поле, удаляя существующее имя.   -  person Fnord23    schedule 16.04.2012


Ответы (3)


После того, как я целый день ломал голову над этой проблемой, не найдя убедительного ответа в документации Apple, я решил поделиться найденным решением на случай, если кто-то еще борется с той же проблемой.

Согласно документации, как упоминалось в исходном плакате, методы control:textShouldBeginEditing и control:textShouldEndEditing из NSControlTextEditingDelegate должны вызываться непосредственно в делегате:

Это сообщение отправляется элементом управления непосредственно своему объекту делегата.

Кроме того, Apple выпустила технические вопросы и ответы под заголовком Обнаружение начала и конца редактировать сеансы ячейки в NSTableView, где четко указано следующее:

A: Как определить начало и конец сеанса редактирования ячейки в NSTableView?

Чтобы определить, когда пользователь собирается начать и завершить сеанс редактирования ячейки в NSTableView, вы должны быть назначены делегатом этой таблицы и реализовать следующие методы делегата NSControl:

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

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

Таблица перенаправляет сообщение делегата, которое она получает из текстового представления, в ваш объект делегата, используя метод control:textShouldEndEditing:. Таким образом, ваш делегат может быть проинформирован о том, какой элемент управления редактор поля текстового представления действует от его имени.

Я не нашел ничего в документации Apple, указывающей на что-то иное, и если кто-то найдет, указатель документации будет действительно ценен.

На самом деле это кажется верным, если используется NSTableView на основе ячеек. Но как только вы измените таблицу на таблицу на основе представления, метод делегата больше не вызывается для объекта делегата таблицы.

Решение

Однако некоторые эвристические тесты, которые я выполнил, показали, что эти методы делегата вызываются для делегата таблицы на основе представления, если (и, насколько мне известно: и только если):

  • Делегат таблицы установлен.
  • Делегат редактируемого элемента управления установлен.

Если вы удалите любого делегата, методы протокола NSControlTextEditingDelegate вызываться не будут.

Согласно (единственной) документации, неожиданной является установка делегата редактируемого элемента управления. С другой стороны, настройка объекта-делегата на получение уведомлений делегата звучит для меня довольно интуитивно, и именно поэтому я в первую очередь попробовал. Но есть загвоздка! Любопытно, однако, что этого недостаточно. Если делегат таблицы удален, методы NSControlTextEditingDelegate не будут вызываться, даже если установлен делегат редактируемого элемента управления (что для меня самое странное).

Надеюсь, это поможет кому-то еще не терять время на эту проблему.

person Enrico M. Crisostomo    schedule 16.06.2014
comment
Это помогло мне. В моем случае возникло дополнительное осложнение: я устанавливал tableView.delegate в awakeFromNib (хотя у меня были установлены привязки для tableview в моем nib)... Я все еще не получал обратных вызовов. После того, как я удалил строку в коде и установил делегата в nib, это сработало. - person Z S; 22.11.2014
comment
Спасибо. Шесть лет спустя, и я все еще никогда бы не догадался, что NSTableView нужен набор делегатов, даже если никакие методы этого делегата не были реализованы, для вызова методов NSControlTextEditingDelegate. Сумасшествие, но это работает.. - person Jeff Hay; 13.03.2020

в своем вопросе вы упоминаете вставку «управляемого объекта», и это было проблемой. Кажется, что вы используете таблицу на основе представления, но метод textShouldEndEditing: вызывается только для таблиц на основе ячеек.

person SystematicFrank    schedule 18.07.2012

Я переопределяю -(void)awakeFromInsert; в управляемом объекте (подклассе), чтобы создать уникальное значение по умолчанию для свойства имени.

Кроме того, я не переопределял метод -(BOOL)textShouldEndEditing: в табличном представлении. Вместо этого я проверяю, является ли вновь введенное свойство-имя уникальным в управляемом объекте (подклассе) -(BOOL)validate<Key>:error:.

Вместе эти две стратегии приводят к уникальным свойствам имен во всех управляемых объектах.

Возможно, я мог бы заставить NSTextFieldCell перейти в режим редактирования, в результате чего -(BOOL)textShouldEndEditing: вызывался бы каждый раз.


Некоторые замечания, хотя:

Кажется, что -(BOOL)textShouldEndEditing: возвращает НЕТ, когда -(BOOL)validate<Key>:error: возвращает НЕТ.

Оба метода -(BOOL)textShouldEndEditing: и -(BOOL)validate<Key>:error: вызываются только тогда, когда пользователь действительно вносит изменения в свойство.

person Fnord23    schedule 16.04.2012
comment
Запоздалое примечание для тех, кто найдет этот ответ с той же проблемой, что и я: когда содержимое текстового поля не изменилось, вы получаете -controlTextDidEndEditing:, а не -control:textShouldEndEditing:. - person Noah Witherspoon; 03.06.2017