Cocoa 取消按钮选择器的工作方式与其他按钮不同';选择器

Cocoa 取消按钮选择器的工作方式与其他按钮不同';选择器,cocoa,unrecognized-selector,cancel-button,Cocoa,Unrecognized Selector,Cancel Button,我有一个面板xib,它由类FooController拥有。FooController还具有到的出口 面板的“取消”和“继续”按钮 我后来决定回收这个面板,供应用程序代理的终止例程使用。当我将选择器分配给按钮时,我发现“继续/保存”按钮和以编程方式添加的DontSave按钮可以接受应用程序委托类中定义的选择器方法。但Cancel按钮会导致“无法识别的选择器”错误,除非其选择器是在所有者类FooController中定义的 好吧,这似乎合乎逻辑。为了保持一致,我还在FooController类中设置

我有一个面板xib,它由类FooController拥有。FooController还具有到的出口 面板的“取消”和“继续”按钮

我后来决定回收这个面板,供应用程序代理的终止例程使用。当我将选择器分配给按钮时,我发现“继续/保存”按钮和以编程方式添加的DontSave按钮可以接受应用程序委托类中定义的选择器方法。但Cancel按钮会导致“无法识别的选择器”错误,除非其选择器是在所有者类FooController中定义的

好吧,这似乎合乎逻辑。为了保持一致,我还在FooController类中设置了继续/保存和DontSave选择器。但是,它们会生成“无法识别的选择器”错误

因此,Cancel按钮要求其选择器位于FooController类中。继续/保存和DontSave按钮要求其选择器位于appDelegate类中。但这三个按钮都明确归FooController所有;正如您在下面的代码中所看到的,甚至添加的DontSave按钮也被显式分配给FooController拥有的面板的contentView:

- (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.
// ...
}

我以前注意到典型的取消功能倾向于自动工作。例如,退出键会自动调用您标题为“取消”的任何按钮。这里可能有类似的幕后机器在工作。如果是这样,我希望我能更好地理解发生了什么。就目前情况而言,我担心这些交叉选择器有一天可能会中断,即使它们目前都可以正常工作。不一致性令人不安。

操作应接受发送方作为参数。应采取以下形式:

- (void)someActionName:(id)sender;
大多数标准调用都是这样工作的。如果要使用转义键使用的相同取消机制,请使用NSResponder的-cancelOperation:(注意末尾的冒号-这是标准操作,发送方是唯一的参数形式)

而且,我没看到你为你的按钮设定目标。目标动作机制意味着您的按钮可能有一个目标,但应该有一个动作。您正在设置按钮的操作,但如果您没有设置其目标,则它们是“无目标”,这意味着Cocoa会爬升响应器链,查找响应您在操作中设置的选择器的第一个对象


这是我能告诉你的最好的细节。您需要更详细地了解您的体系结构(类名、准确的错误消息、丢失的更多代码等),以获得更详细的答案。

如果有人在处理类似问题,下面是修订后的代码,其中包含Joshua建议的更改:

(1) 调用setTarget。(setTarget是NSButton超类NSControl的一种方法。)

(2) 一个冒号被添加到选择器中,现在它们接受了一个“sender”参数

- (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.
// ...
}
以下是其中一个选择器的修订声明(以前不接受任何参数):

所有这些代码都在应用程序委托类中,而不是FooController中


至于为什么取消功能在其他按钮工作正常的情况下被之前的抖动代码打乱了平衡,这对我来说仍然是个谜。但是,现在所有三个按钮都并行设置,并且都按预期执行,我对代码的稳定性感到满意。

谢谢,这比我要求的信息要好。我一直在各地使用无目标控件和无参数选择器——尽管一切正常,但代码可能不稳定。我添加了目标和发送方参数,所有内容都在appDelegate中一致工作。(我已将修订后的代码作为单独的答案发布,以供参考。)
- (void) cancelQuit:(id)sender;