Objective-C откликается на ToSelector - PullRequest
19 голосов
/ 01 января 2011

Из того, что я узнал до сих пор: в Objective-C вы можете отправлять любое сообщение любому объекту.Если объект реализует правильный метод, он будет выполнен, иначе ничего не произойдет.Это связано с тем, что перед отправкой сообщения Objective-C будет выполнять responseds ToSelector .

Я надеюсь, что пока прав.

Я сделал небольшую программу для тестирования, в которой действие вызывается при каждом перемещении ползунка.Также для тестирования я установил отправителя в NSButton, но на самом деле это NSSlider.Теперь я спросил объект, будет ли он отвечать на setAlternateTitle .Пока NSButton будет делать, а NSSlider - нет.Если я выполню код и сам responsedsToSelector , он скажет, что объект не будет реагировать на этот селектор.Если я проверю что-то еще, например intValue , оно ответит.Так что мой код пока в порядке.

- (IBAction)sliderDidMove:(id)sender
{
    NSButton *slider = sender;

    BOOL responds =
    [slider respondsToSelector:@selector(setAlternateTitle)];

    if(responds == YES)
    {
        NSLog(@"YES");        
    }
    else
    {
        NSLog(@"NO");
    }

    [slider setAlternateTitle:@"Hello World"];
}

Но когда я на самом деле отправляю сообщение setAlternateTitle, программа падает, и я не совсем уверен, почему.Разве он не должен делать responseds ToSelector перед отправкой сообщения?

Ответы [ 4 ]

150 голосов
/ 01 января 2011

Прежде всего, имя метода (его селектор) включает все части и символы двоеточия, как сказал mvds.

Во-вторых, метод -respondsToSelector: не вызывается средой выполнения, он обычно вызывается пользователем (вами или API, которые хотят знать, например, отвечает ли делегат на необязательный метод протокола).

Когда вы отправляете сообщение объекту, среда выполнения будет искать реализацию метода в классе объекта (через указатель isa объекта). Это эквивалентно отправке -respondsToSelector:, хотя само сообщение не отправляется. Если реализация метода найдена в классе или в его суперклассах, он вызывается со всеми переданными вами аргументами.

Если нет, то среда выполнения дает сообщению второй шанс быть выполненным. Он начнется с отправки сообщения + (BOOL)resolveInstanceMethod:(SEL)name классу объекта: этот метод позволяет добавить метод во время выполнения к классу: если это сообщение возвращает YES, это означает, что оно может повторно отправить сообщение.

Если это не дает сообщению третий шанс быть выполненным, он отправляет - (id)forwardingTargetForSelector:(SEL)aSelector с помощью селектора, этот метод может вернуть другой объект, который может быть в состоянии ответить селектору от имени фактического получателя, если возвращено объект может ответить, метод выполняется и значение возвращается так, как если бы оно было возвращено исходным сообщением. (Примечание: это доступно начиная с OS X 10.6 или iOS 4.)

Если возвращаемый объект имеет значение nil или self (чтобы избежать бесконечных циклов), среда выполнения дает сообщению четвертый шанс выполнить метод ... Он отправляет сообщение - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector, чтобы получить сигнатуру метода для построения вызова. Если он указан, то вызов отправляется через сообщение - (void)forwardInvocation:(NSInvocation *)anInvocation. В этом методе вы можете анализировать вызов и создавать другие сообщения для отправки другим целям любым удобным для вас способом, а затем вы можете установить возвращаемое значение вызова ... Это значение будет действовать как возвращаемое значение исходного сообщения.

Наконец, если объект не возвращает сигнатуру метода, тогда среда выполнения отправляет сообщение - (void)doesNotRecognizeSelector:(SEL)aSelector вашему объекту, реализация этого метода в классе NSObject выдает исключение.

7 голосов
/ 01 января 2011

С одной стороны, selector - это не только «имя» сообщения, но и то, что следует, то есть аргументы и их имена.

Таким образом, правильный селектор для некоторых -(void)setAlternateTitle:(NSString*)str будет

@selector(setAlternateTitle:)

с :

Что касается вашей проблемы: если класс respondsToSelector() и вы выполняете этот селектор, вы не должны получить сбой при отправке неизвестного селектора. Какой тип журнала вы видите в окне отладки?

(пс. Почему бы не включить [slider setAlternateTitle:...] в условный блок if ( responds ) { ... }?)

2 голосов
/ 08 сентября 2011

Существует метод +instancesRespondToSelector:.Как следует из названия, он говорит вам, реализуют ли экземпляры класса этот метод.

2 голосов
/ 01 января 2011

"Это связано с тем, что перед отправкой сообщения Objective-C выполнит отклики на запрос."Если объект не отвечает на селектор, он потерпит крах во время выполнения.Там нет автоматической проверки системой.Если система проверки выполняла проверку, мы никогда не должны получать исключение «нераспознанный селектор отправлен в экземпляр».

Пожалуйста, исправьте меня, если я неправ

РЕДАКТИРОВАТЬ: Это не прямой сбой, но по умолчанию результат будет завершен.Вся последовательность уже объяснена в комментариях и других ответах, поэтому я не собираюсь писать это снова.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...