Аргументы в @selector
Есть ли способ передать аргументы в селекторе?
Пример:
У меня есть этот метод
- (void)myMethod:(NSString*)value1 setValue2:(NSString*)value2{
}
и мне нужно вызвать эту функцию через селектор, передающий два аргумента.
[NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(/*my method*/) userInfo:nil repeats:YES];
Как я могу это сделать?
Ответы
Ответ 1
Вы можете использовать метод NSTimer
:
+ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)seconds
invocation:(NSInvocation *)invocation
repeats:(BOOL)repeats;
Вместо этого, поскольку объект NSInvocation
позволит вам передавать аргументы; объект NSInvocation
, так как docs определяет его:
a Objective-C сообщение отображается статическим, то есть это действие, превращенное в объект.
В то время как создание объекта NSTimer
с использованием селектора требует формата метода:
- (void)timerFireMethod:(NSTimer*)theTimer
An NSInvocation
позволяет вам установить цель, селектор и аргументы, которые вы передаете:
SEL selector = @selector(myMethod:setValue2:);
NSMethodSignature *signature = [MyObject instanceMethodSignatureForSelector:selector];
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
[invocation setSelector:selector];
NSString *str1 = @"someString";
NSString *str2 = @"someOtherString";
//The invocation object must retain its arguments
[str1 retain];
[str2 retain];
//Set the arguments
[invocation setTarget:targetInstance];
[invocation setArgument:&str1 atIndex:2];
[invocation setArgument:&str2 atIndex:3];
[NSTimer scheduledTimerWithTimeInterval:0.1 invocation:invocation repeats:YES];
Где MyObject
- это класс, объявленный и реализованный myMethod:setValue2:
on - instanceMethodSignatureForSelector:
- это функция удобства, объявленная в NSObject
, которая возвращает объект NSMethodSignature
для вас, который должен быть передан в NSInvocation
.
Кроме того, отметим, что с setArgument:atIndex:
индексы для аргументов, которые должны быть переданы методу, установленному как начало селектора в индексе 2. В документах:
Индексы 0 и 1 указывают скрытые аргументы self и _cmd соответственно; вы должны установить эти значения непосредственно с помощью методов setTarget: и setSelector:. Используйте индексы 2 и выше для аргументов, обычно передаваемых в сообщении.
Ответ 2
Для scheduledTimerWithTimeInterval:
, селектор, который вы передаете, может иметь только один аргумент. Кроме того, его одним аргументом должен быть объект NSTimer *
. Другими словами, селектор должен иметь следующую форму:
- (void)timerFireMethod:(NSTimer*)theTimer
Что вы можете сделать, это сохранить аргументы в словаре userInfo
и вызвать селектор, который вы хотите, из обратного вызова таймера:
- (void)startMyTimer {
/* ... Some stuff ... */
[NSTimer scheduledTimerWithTimeInterval:0.1
target:self
selector:@selector(callMyMethod:)
userInfo:[NSDictionary dictionaryWithObjectsAndKeys:someValue,
@"value1", someOtherValue, @"value2", nil]
repeats:YES];
}
- (void)callMyMethod:(NSTimer *)theTimer {
NSString *value1 = [[theTimer userInfo] objectForKey:@"value1"];
NSString *value2 = [[theTimer userInfo] objectForKey:@"value2"];
[self myMethod:value1 setValue2:value2];
}
Ответ 3
Похож на работу для блоков (при условии, что это предназначено для Snow Leopard.)
-jcr
Ответ 4
Блоки теперь кажутся очевидным ответом... но есть еще одна идиома, которая была очень распространена в классической среде исполнения, рассортировала ваши аргументы в одном объекте:
- (void)doMyMethod:(NSDictionary *)userInfo
{
[self myMethod: [userInfo objectForKey:@"value1"] setValue2: [userInfo objectForKey:@"value2"]];
}
- (void)myMethod:(NSString*)value1 setValue2:(NSString*)value2{
}
теперь вы можете отправить
[self performSelector:@selector(doMyMethod:) withObject:@{@"value1":@"value1",@"value2":@"value2"}];
Ответ 5
@selector(myMethod:setValue2:)
Поскольку селектор для вашего метода не просто называется myMethod
, а вместо него myMethod:setValue2:
.
Также (и я мог бы быть вне базы здесь), я считаю, что технически вы можете отбросить слова между двоеточиями и, следовательно, также использовать @selector(myMethod::)
, но не цитируйте меня на этом, если другие не подтвердят его.