Почему я не могу подключить свое меню к моему контроллеру представления IBAction?

У меня есть приложение, основанное на документах. Я только что создал пункты меню в раскадровке и IBActions в своем контроллере представления. Однако обычный способ подключения действия к цели не работает.

-(IBAction) markAsHidden:(id)sender;
-(IBAction) markAsVisible:(id)sender;
-(IBAction) toggleHidden:(id)sender;

Вот что я вижу, когда из своего пункта меню я нажимаю Ctrl и щелкаю мышью из меню в View Controller. Он не показывает мои IBActions.

Есть идеи ? Мои 2 цента предполагают, что это связано с тем, что приложение основано на документах, но... не совсем уверен

меню подключения


person Thomas    schedule 22.02.2015    source источник
comment
Как бы вы ни подключались, Xcode считает, что вы хотите использовать действие для перехода к другому контроллеру. Можете ли вы выбрать пункт меню, а затем подключить его, перетащив его из редактора соединений (правая боковая панель экрана)?   -  person Phillip Mills    schedule 22.02.2015
comment
@PhillipMills Я тоже пробовал это (из отправленных действий -> селектор) в контроллер просмотра, но результат тот же   -  person Thomas    schedule 22.02.2015
comment
@Thomas Появляются ли ваши IBActions в HUD, если вы подключаетесь к первому ответчику сцены приложения? Подключение к первому ответчику сцены приложения позволило мне подключить пункты меню к IBActions в моих контроллерах представления.   -  person Mark Szymczyk    schedule 23.02.2015
comment
@MarkSzymczyk, ты прав, это работает !!   -  person Thomas    schedule 23.02.2015
comment
@MarkSzymczyk Раньше я безуспешно пытался подключиться к первому ответчику сцены View Controller. если вы хотите сделать это ответом, я приму его   -  person Thomas    schedule 23.02.2015


Ответы (3)


Почему я не могу подключить свое меню к моему контроллеру представления IBAction?

Потому что ваши пункты меню и контроллер представления находятся в разных сценах в раскадровке. Вы можете думать о сцене как о независимом графе объектов, которые создаются, когда сцена загружается из раскадровки. Объекты в разных сценах нельзя соединить в раскадровке, потому что они не загружаются одновременно.

Ради интереса попробуйте создать экземпляр вашего контроллера представления в Application Scene вашей раскадровки. Для этого вам, вероятно, потребуется перетащить старый добрый экземпляр NSObject в сцену, а затем установить его тип. Как только вы это сделаете, вы обнаружите, что вы можете перетаскивать соединение из пункта меню в этот контроллер представления, как вы и ожидали, но вы не можете перетаскивать соединение с другим объектом того же типа в другом месте. сцена.

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

Мои 2 цента предполагают, что это связано с тем, что приложение основано на документах.

Нет, это не имеет к этому никакого отношения. У вас будет та же проблема в приложении, которое не основано на документах. У вас также была бы та же проблема, если бы ваше приложение было основано на .xib, а не на раскадровках, поскольку контроллер, к которому вы пытаетесь подключиться, находился бы в совершенно другом файле .xib.

Простое решение, как уже описал Марк, — использовать цепочку респондеров. Прокси-объект First Responder является частью каждой сцены, поэтому вы всегда можете подключиться к нему. Когда вы подключаете элемент меню к первому ответчику, его целью будет nil, что говорит NSMenu обходить цепочку ответчика, пока не будет найден объект, который отвечает на сообщение о действии пункта меню. Затем он отправляет сообщение этому объекту.

person Caleb    schedule 23.02.2015
comment
Просто для ясности: размещение экземпляра вашего класса контроллера представления в сцене приложения интересно для иллюстрации того, что проблема заключается в соединении между сценами, но его не следует оставлять там. Это не будет работать так, как хочет OP, и приведет к путанице из-за блуждающего контроллера представления, не подключенного к какому-либо представлению. - person Ken Thomases; 23.02.2015
comment
@KenThomases Правильно! Я абсолютно согласен. Я только хотел проиллюстрировать проблему, а не предлагать ОП попытаться создать настоящее приложение с контроллером представления в сцене приложения. Я обновлю. - person Caleb; 23.02.2015
comment
спасибо за подробный ответ. какова цепочка первого ответчика в сцене? Сцена приложения -> Сцена контроллера представления (по умолчанию = наш контроллер представления)? - person Thomas; 24.02.2015
comment
Apple полностью задокументировала цепочку ответчика, так что я не буду пытаться сделать это снова в комментарии. Просто поймите, что First Responder в редакторе раскадровки — это не отдельный объект в вашем коде. Он представляет любой объект, который оказывается первым ответчиком, то есть первым объектом в цепочке ответчиков в любой данный момент. - person Caleb; 24.02.2015

Подключите пункты меню к первому ответчику сцены приложения. Когда вы подключаетесь к первому ответчику сцены приложения, IBActions вашего контроллера представления должны отображаться в списке доступных действий HUD вместо последовательностей действий, показанных в HUD вашего снимка экрана.

person Mark Szymczyk    schedule 23.02.2015
comment
Я не принял, потому что тем временем был другой ответ, более подробный (извините), поэтому я проголосовал за вас, чтобы компенсировать это - person Thomas; 24.02.2015
comment
@MartinDelille Проверьте соединения. Еще одна вещь, которую нужно проверить в своем коде, — это имена ваших действий. Если есть опечатка, меню может быть отключено. Недавно у меня была проблема, когда меню было отключено, потому что в моем коде не хватало двоеточия в конце имени действия. Если это не поможет, задайте новый вопрос. - person Mark Szymczyk; 15.07.2016

Если вы переводите проект с Objective C на Swift, не повторяйте моей ошибки. При написании IBAction пишите так:

 @IBAction func someAction(_ sender:AnyObject) {
     // this will work
 }

Не пропускайте символ подчеркивания перед sender, иначе интерфейсный конструктор не сможет подключиться к вашему действию, как здесь:

 @IBAction func someAction(sender:AnyObject) {
     // this won't work and IB won't connect to this action
     // because sender will be part of the symbol name
 }
person jvarela    schedule 28.12.2016