Objective-C: вызов селекторов с несколькими аргументами - PullRequest
138 голосов
/ 19 июня 2009

В MyClass.m я определил

- (void) myTest: (NSString *) withAString{
    NSLog(@"hi, %@", withAString);
}

и соответствующее объявление в MyClass.h. Позже я хочу позвонить

[self performSelector:@selector(mytest:withAString:) withObject: mystring];

в MyClass.m, но я получаю сообщение об ошибке, похожее на * Завершение работы приложения из-за необработанного исключения «NSInvalidArgumentException», причина: «* - [MyClass myTest: withAtring:]: нераспознанный селектор, отправленный экземпляру 0xe421f0 '

Я попробовал более простой случай с селектором, который не принимал аргументов, который выводил строку на консоль, и это работало просто отлично. Что не так с кодом и как я могу это исправить? Спасибо.

Ответы [ 7 ]

307 голосов
/ 19 июня 2009

В Objective-C подпись селектора состоит из:

  1. Имя метода (в данном случае это будет «myTest») (обязательно)
  2. A ':' (двоеточие) после имени метода, если метод имеет вход.
  3. Имя и ':' для каждого дополнительного ввода.

Селекторы не знают:

  1. Типы ввода
  2. Тип возврата метода.

Вот реализация класса, где метод executeMethodsViaSelectors выполняет другие методы класса с помощью селекторов:

@implementation ClassForSelectors
- (void) fooNoInputs {
    NSLog(@"Does nothing");
}
- (void) fooOneIput:(NSString*) first {
    NSLog(@"Logs %@", first);
}
- (void) fooFirstInput:(NSString*) first secondInput:(NSString*) second {
    NSLog(@"Logs %@ then %@", first, second);
}
- (void) performMethodsViaSelectors {
    [self performSelector:@selector(fooNoInputs)];
    [self performSelector:@selector(fooOneInput:) withObject:@"first"];
    [self performSelector:@selector(fooFirstInput:secondInput:) withObject:@"first" withObject:@"second"];
}
@end

Метод, для которого вы хотите создать селектор, имеет один вход, поэтому вы должны создать селектор для него следующим образом:

SEL myTestSelector = @selector(myTest:);
134 голосов
/ 19 июня 2009

Ваш метод подписи:

- (void) myTest:(NSString *)

withAString является параметром (имя вводит в заблуждение, похоже, оно является частью подписи селектора).

Если вы вызываете функцию следующим образом:

[self performSelector:@selector(myTest:) withObject:myString];

Это будет работать.

Но, как предлагали другие авторы, вы можете переименовать метод:

- (void)myTestWithAString:(NSString*)aString;

И звоните:

[self performSelector:@selector(myTestWithAString:) withObject:myString];
13 голосов
/ 05 ноября 2012

@ Шейн Арни

performSelector:withObject:withObject:

Вы также можете упомянуть, что этот метод предназначен только для передачи максимум 2 аргументов, и его нельзя отложить. (например, performSelector:withObject:afterDelay:).

странно, что apple поддерживает только 2 объекта для отправки и не делает его более универсальным.

7 голосов
/ 18 июля 2009

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

-(void)myTestWithString:(NSString *)sourceString comparedTo:(NSString *)testString ;

Создание селекторов для методов, которые принимают несколько аргументов, совершенно допустимо (например, @selector (myTestWithString: сравнениеTo :)). Однако метод executeSelector позволяет передать только одно значение myTest, который, к сожалению, имеет более одного параметра. Он выдаст ошибку и сообщит, что вы не указали достаточно значений.

Вы всегда можете переопределить свой метод для получения коллекции, так как это единственный параметр:

-(void)myTestWithObjects:(NSDictionary *)testObjects ;

Однако есть более элегантное решение (не требующее рефакторинга). Ответ заключается в использовании NSInvocation вместе с методами setArgument:atIndex: и invoke.

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

Удачи!

3 голосов
/ 19 июня 2009

Ваша подпись метода не имеет смысла, вы уверены, что это не опечатка? Мне не ясно, как он компилируется, хотя, возможно, вы получаете предупреждения, которые игнорируете?

Сколько параметров вы ожидаете от этого метода?

2 голосов
/ 19 июня 2009

думаю, что класс должен быть определен как:

- (void) myTestWithSomeString:(NSString *) astring{
    NSLog(@"hi, %s", astring);
}

У вас есть только один параметр, поэтому у вас должен быть только один:

Возможно, вы захотите использовать% @ в вашем NSLog - это просто хорошая привычка - потом выписать любой объект - не только строки.

0 голосов
/ 12 января 2016

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

Вы можете решить, следует ли реализовывать такие функции или нет; здесь нет выделенный API для любой из перечисленных функций, поэтому предоставление их это конкурентное преимущество.

В документе Apple говорится, что для этой функции и некоторых других ожидаемых функций в настраиваемой клавиатуре нет API. поэтому вам нужно найти собственную логику для реализации этого.

...