Аргументы в @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::), но не цитируйте меня на этом, если другие не подтвердят его.