Objective-C: Вызов селекторов с несколькими аргументами

В 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 '

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

Ответ 1

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

- (void) myTest:(NSString *)

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

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

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

Он будет работать.

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

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

И вызов:

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

Ответ 2

В Objective-C сигнатура селектора состоит из:

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

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

  • Типы ввода
  • Возвращает тип метода.

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

@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:);

Ответ 3

@Shane Arney

performSelector:withObject:withObject:

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

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

Ответ 4

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

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

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

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

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

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

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

Удачи!

Ответ 5

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

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

Ответ 6

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

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

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

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

Ответ 7

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

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

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