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

138

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

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

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

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

в MyClass.m, но я получаю ошибку, похожую на * Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '* - [MyClass myTest: withAtring:]: нераспознанный селектор, отправленный экземпляру 0xe421f0 & apos;

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

Ваш пост спрашивает о «нескольких аргументах», но вы используете только один. Теперь мне любопытно, как кто-то может сделать это с несколькими аргументами, за исключением того, что они заключены в массив / dict / что угодно. RonLugge

Ваш Ответ

7   ответов
305

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

  1. The name of the method (in this case it would be 'myTest') (required)
  2. A ':' (colon) following the method name if the method has an input.
  3. A name and ':' for every additional input.

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

  1. The input types
  2. The method's return type.

Вот реализация класса, где метод 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:);
Хороший ответ. Для пояснения, имя селектора ДОЛЖНО иметь хотя бы одну часть, которая может принимать или не принимать параметр & # x2014; если это так, у него должно быть двоеточие. Имена селекторов с двумя или более частями ДОЛЖНЫ иметь двоеточие после КАЖДОЙ части & # x2014; недопустимо иметь селектор вида «-useFoo: andBar: toDoSomething».
как насчет входных параметров целых чисел? что делать в этом случае?
Спасибо за это. Я боролся с этим некоторое время, рад за помощь!
+100: это круто! Я не знал о возможности использовать несколько "withObject:" параметры. Я бы сказал это сто раз, если бы мог ...
Вам нужно будет обернуть целое число в объект NSNumber (см.developer.apple.com/library/ios/#documentation/Cocoa/Reference/…) и получить целочисленное значение в теле вызываемого метода. Это может быть немного многословно (и я не нашел лучшего способа обойти это), но это работает отлично.
13

@ Шейн Арни

performSelector:withObject:withObject:

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

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

Спасибо за информацию. Я не мог заставить задержку работать, и теперь я знаю, почему. К вашему сведению, чтобы обойти ограничение двух объектов, я передал массив, а затем использовал его в методе.
3

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

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

Извините, вы пишете. Я напечатал его и попытался упростить его вместо того, чтобы копировать и вставлять свой код, но в процессе я допустил ошибку. Я ожидаю, что этот метод будет принимать один параметр; Строка, которую я хотел бы напечатать. Stu
134

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

- (void) myTest:(NSString *)

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

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

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

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

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

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

И позвоните:

[self performSelector:@selector(myTestWithAString:) withObject:myString];
Теперь, когда я вижу, что люди получили пользу от этого ответа, я пересмотрел свой ответ; Я хотел бы предложить, чтобы вызов был просто: - (void) testWithString: (NSString *) aString;
7

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

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

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

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

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

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

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

Удачи!

0

iOS users also expect autocapitalization: In a standard text field, the first letter of a sentence in a case-sensitive language is automatically capitalized.

You can decide whether or not to implement such features; there is no dedicated API for any of the features just listed, so providing them is a competitive advantage.

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

2

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

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

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

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

Похожие вопросы