Селектор для кнопки Отмена работает иначе, чем селекторы других кнопок - PullRequest
0 голосов
/ 27 ноября 2011

У меня есть панель XIB, которая принадлежит классу FooController.FooController также имеет выходы для кнопок «Отмена» и «Продолжить» на панели.

Позже я решил переработать эту панель для использования в процедуре завершения работы делегата приложения.Когда я назначил селекторам кнопки, я обнаружил, что кнопка «Приступить / Сохранить» и программно добавленная кнопка «DontSave» могут принимать в качестве методов селектора методы, определенные в классе делегата приложения.Но кнопка «Отмена» вызовет ошибки «нераспознанный селектор», если только его селектор не был определен в классе владельца, FooController.

Хорошо, что кажется логичным.Чтобы быть последовательным, я также установил селекторы Proceed / Save и DontSave в классе FooController.Но тогда они будут генерировать ошибки «нераспознанного селектора».

Таким образом, для кнопки отмены требуется , чтобы ее селектор находился в классе FooController.Кнопки Proceed / Save и DontSave требуют, чтобы их селекторы находились в классе appDelegate.Но все три кнопки явно принадлежат FooController;как вы можете видеть в приведенном ниже коде, даже добавленная кнопка DontSave явно назначена для contentView панели, принадлежащей FooController:

- (void) adviseOfPendingChangesBeforeQuit {

// Open the panel.
[NSBundle loadNibNamed:@"panelConfirmation" owner:self.fooController];

// Add an extra "Don't Save" button.
NSButton *btnDontSave = [[NSButton alloc] initWithFrame:NSMakeRect(12.0f, 12.0f, 106.0f, 32.0f)]; 
[btnDontSave setTitle:NSLocalizedString(@"Don't Save", @"Don't Save")];
[btnDontSave setButtonType:NSMomentaryPushInButton];
[btnDontSave setBezelStyle:NSRoundedBezelStyle];
[btnDontSave setAction:@selector(dumpChangesAndQuitPerPendingConfirmPanel)]; // method defined in this, the appDelegate class
NSView *viewToReceiveNewButton = [self.fooController.panelForInput contentView];
[viewToReceiveNewButton addSubview:btnDontSave];
[btnDontSave release];

// Change the “proceed” button’s title to "Save", make it the default, and assign its action.
[self.fooController.btnProceed setTitle:NSLocalizedString(@"Save", @"Save")];
[self.fooController.btnProceed setKeyEquivalent:@"\r"];
[self.fooController.btnProceed setAction:@selector(saveAndQuitPerPendingConfirmPanel)]; // method defined in this, the appDelegate class

// Assign “Cancel” button's action.
[self.fooController.btnCancel setAction:@selector(callCancelQuit)];

// Finish setting up the panel and launch it.
// ...
}

Я заметил ранее, что типичные функции Cancel имеют тенденцию работать автоматически.Например, клавиша Escape автоматически вызывает любую кнопку, которую вы назвали «Отмена». Возможно, здесь работает аналогичный механизм за кадром.Если это так, я бы хотел лучше понять, что происходит.В настоящее время я обеспокоен тем, что эти перекрещивающиеся селекторы могут когда-нибудь сломаться, хотя все они пока работают нормально.Несоответствие вызывает беспокойство.

Ответы [ 2 ]

2 голосов
/ 27 ноября 2011

Действия должны принимать отправителя в качестве аргумента. Следует принять форму:

- (void)someActionName:(id)sender;

Большинство стандартных вызовов работают таким образом. Если вы хотите использовать тот же механизм отмены, который использует клавиша Escape, используйте -CancelOperation NSResponder: (обратите внимание на двоеточие в конце - это стандартная форма действия с аргументом отправителя как единственного аргумента).

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

Это лучшее, что я могу вам рассказать с предоставленной вами информацией. Чтобы получить более подробные ответы, вам нужно быть более точным в своей архитектуре (имена классов, точные сообщения об ошибках, больше кода, если таковой отсутствует, и т. Д.).

0 голосов
/ 27 ноября 2011

Если кто-то имеет дело с подобной проблемой, вот пересмотренный код, включающий изменения, предложенные Джошуа:

(1) вызывается setTarget.(setTarget - это метод суперкласса NSButton, NSControl.)

(2) К селекторам добавлено двоеточие, теперь они принимают аргумент «отправитель».

- (void) adviseOfPendingChangesBeforeQuit {

// Open the panel.
[NSBundle loadNibNamed:@"panelConfirmation" owner:self.fooController];

// Add an extra "Don't Save" button.
NSButton *btnDontSave = [[NSButton alloc] initWithFrame:NSMakeRect(12.0f, 12.0f, 106.0f, 32.0f)]; 
[btnDontSave setTitle:NSLocalizedString(@"Don't Save", @"Don't Save")];
[btnDontSave setButtonType:NSMomentaryPushInButton];
[btnDontSave setBezelStyle:NSRoundedBezelStyle];
[btnDontSave setAction:@selector(dumpChangesAndQuitPerPendingConfirmPanel:)]; 
[btnDontSave setTarget:self]; 
NSView *viewToReceiveNewButton = [self.fooController.panelForInput contentView];
[viewToReceiveNewButton addSubview:btnDontSave];
[btnDontSave release];

// Change the “proceed” button’s title to "Save", make it the default, and assign its action.
[self.fooController.btnProceed setTitle:NSLocalizedString(@"Save", @"Save")];
[self.fooController.btnProceed setKeyEquivalent:@"\r"];
[self.fooController.btnProceed setAction:@selector(saveAndQuitPerPendingConfirmPanel:)]; 
[self.fooController.btnProceed setTarget:self];

// Assign “Cancel” button's action.
[self.fooController.btnCancel setAction:@selector(cancelQuit:)];
[self.fooController.btnCancel setTarget:self];

// Finish setting up the panel and launch it.
// ...
}

Вотпересмотренное объявление одного из селекторов (которое ранее не принимало аргументов):

- (void) cancelQuit:(id)sender;

Весь этот код находится в классе делегата приложения, а не в FooController.

Что касается того, почему была отменена функция Cancelсбил с баланса предыдущий шаткий код, когда другие кнопки работали нормально - это должно остаться для меня загадкой.Но теперь, когда все три кнопки настроены параллельно, и все они работают должным образом, я удовлетворен стабильностью кода.

...