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'
Я попробовал более простой случай с селектором, который не принимал аргументов, которые выводили строку на консоль, и это работало просто отлично. Что не так с кодом и как я могу это исправить? Благодарю.
8 ответов
Ваша подпись метода:
- (void) myTest:(NSString *)
Параметр withAString оказывается (имя вводит в заблуждение, похоже, оно является частью подписи селектора).
Если вы вызываете функцию следующим образом:
[self performSelector:@selector(myTest:) withObject:myString];
Это будет работать.
Но, как предложили другие авторы, вы можете переименовать метод:
- (void)myTestWithAString:(NSString*)aString;
И позвоните:
[self performSelector:@selector(myTestWithAString:) withObject:myString];
В Objective-C подпись селектора состоит из:
- Имя метода (в данном случае это будет "myTest") (обязательно)
- ':' (Двоеточие) после имени метода, если метод имеет вход.
- Имя и ":" для каждого дополнительного ввода.
Селекторы не знают:
- Типы ввода
- Тип возврата метода.
Вот реализация класса, где метод 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:);
@ Шейн Арни
performSelector:withObject:withObject:
Вы также можете упомянуть, что этот метод предназначен только для передачи максимум 2 аргументов, и его нельзя отложить. (такие как performSelector:withObject:afterDelay:)
,
странно, что apple поддерживает только 2 объекта для отправки и не делает его более универсальным.
У вашего кода есть две проблемы. Один был идентифицирован и ответил, а другой нет. Во-первых, в вашем селекторе отсутствовало имя его параметра. Однако даже если вы исправите это, строка все равно вызовет исключение, если ваша пересмотренная сигнатура метода все еще содержит более одного аргумента. Допустим, ваш исправленный метод объявлен как:
-(void)myTestWithString:(NSString *)sourceString comparedTo:(NSString *)testString ;
Создание селекторов для методов, которые принимают несколько аргументов, совершенно допустимо (например, @selector(myTestWithString: сравнение To:)). Однако метод executeSelector позволяет передавать только одно значение в myTest, который, к сожалению, имеет более одного параметра. Он выдаст ошибку и скажет, что вы не указали достаточно значений.
Вы всегда можете переопределить свой метод для получения коллекции, так как это единственный параметр:
-(void)myTestWithObjects:(NSDictionary *)testObjects ;
Однако есть более элегантное решение (не требующее рефакторинга). Ответ заключается в использовании NSInvocation вместе с его setArgument:atIndex:
а также invoke
методы.
Я написал статью, включая пример кода, если вы хотите больше подробностей. Основное внимание уделяется многопоточности, но основы все еще применяются.
Удачи!
Ваша подпись метода не имеет смысла, вы уверены, что это не опечатка? Мне не ясно, как он компилируется, хотя, возможно, вы получаете предупреждения, которые игнорируете?
Сколько параметров вы ожидаете этот метод принять?
Думаю, что класс должен быть определен как:
- (void) myTestWithSomeString:(NSString *) astring{
NSLog(@"hi, %s", astring);
}
У вас есть только один параметр, поэтому вы должны иметь только один:
Возможно, вы захотите использовать%@ в вашем NSLog - это просто хорошая привычка - потом выписать любой объект - не только строки.
Сообщение на 2021_10_15 от разработчика Android.
(OC труднее использовать, -_-||)
Вызов селекторов с несколькими аргументами,
вы можете использовать
NSObject performSelector:withObject:withObject
,
но поддерживает только два аргумента !!!
К счастью, вы можете реализовать себя
performSelector withObject X 3
к
objc_msgSend
функция.
#include <objc/message.h>
- (id)performSelector:(SEL)aSelector withObject:(id)object1 withObject:(id)object2 withObject:(id)object3 {
typedef id (*send_type)(id, SEL, id, id, id);
send_type func = (send_type) objc_msgSend;
id retValue = func(self, aSelector, object1, object2, object3);
return retValue;
}
Использование:
- (NSString *)ObjcMsgSendWithString:(NSString *)string withNum:(NSNumber *)number withArray:(NSArray *)array {
NSLog(@" ---> %@, %@, %@", string, number, array[0]);
return @"return 311";
}
- (void)test{
NSString *str = @"字符串objc_msgSend";
NSNumber *num = @20;
NSArray *arr = @[@"数组值1", @"数组值2"];
SEL sel = @selector(ObjcMsgSendWithString:withNum:withArray:);
NSLog(@"1223 ---> %@", [self performSelector:sel withObject:str withObject:num withObject:arr]);
}
Пользователи iOS также ожидают автокапитализацию: в стандартном текстовом поле первая буква предложения в регистрозависимом языке автоматически пишется с заглавной буквы.
Вы можете решить, следует ли реализовывать такие функции; для какой-либо из перечисленных функций нет специального API, поэтому предоставление их является конкурентным преимуществом.
В документе Apple говорится, что для этой функции нет API-интерфейса и какой-либо другой ожидаемой функции в пользовательской клавиатуре. так что вам нужно выяснить свою собственную логику для реализации этого.