2009-08-28 14 views
35

¿Hay alguna manera de que pueda pasar argumentos en el selector?Argumentos en @selector

ejemplo: que tienen este método

- (void)myMethod:(NSString*)value1 setValue2:(NSString*)value2{ 

} 

y necesito llamar a esta función a través de un selector de pasar dos argumentos.

[NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(/*my method*/) userInfo:nil repeats:YES]; 

¿Cómo puedo hacer esto?

Respuesta

56

Usted podría utilizar el método NSTimer:

+ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)seconds 
           invocation:(NSInvocation *)invocation 
            repeats:(BOOL)repeats; 

en cambio, desde un objeto NSInvocation le permitirá pasar argumentos; un objeto NSInvocation es, como la docs definen:

un Objective-C mensaje rindió estático, es decir, que es una acción se convirtió en un objeto.

Si bien la creación de un objeto NSTimer mediante un selector requiere el formato del ser método:

- (void)timerFireMethod:(NSTimer*)theTimer 

Un NSInvocation le permite establecer el objetivo, el selector, y los argumentos que se pasan en:

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]; 

Dónde MyObject es la clase que se declara myMethod:setValue2: y ejecutarse - instanceMethodSignatureForSelector: es una functi conveniencia en declarado en NSObject que devuelve un objeto NSMethodSignature para usted, que se pasará a NSInvocation.

También, tomar nota, con setArgument:atIndex:, los índices de los argumentos que se pasan al método establecido como el inicio de selección en el índice 2. A partir de la documentación:

índices 0 y 1 indican los argumentos ocultos auto y _cmd, respectivamente; debe establecer estos valores directamente con setTarget: y setSelector: methods.Use los índices 2 y mayores para los argumentos normalmente aprobados en un mensaje.

+1

Esta es una mejor respuesta que la mía. Debe hacer esto para evitar contaminar sus implementaciones con métodos innecesarios. –

+3

Tenga en cuenta que, si 'str1' y' str2' no estuvieran asignados estáticamente, los filtraría. 'NSTimer' está documentado como el envío de' -retainArguments' a su objeto de invocación, pero no sería malo para usted enviar '-retainArguments' al objeto de invocación usted mismo. El problema es retener los argumentos usted mismo, y luego decirle a la invocación que los retenga también. ¡No retenga los argumentos de invocación usted mismo! Deje que la invocación lo maneje, y, aquí, deje que el temporizador lo maneje por sí mismo. –

+3

No codifique la clase de 'targetInstance', como se hizo al recuperar la firma del método. Si realmente desea utilizar '+ instanceMethodSignatureForSelector:', puede usar '[[clase de instancia de destino] instanciaMethodSignatureForSelector: selector]', pero eso es innecesariamente complejo: simplemente solicite al objeto en sí la firma del método usando '[targetInstance methodSignatureForSelector: selector]' . –

-2
@selector(myMethod:setValue2:) 

Desde el selector para su método no se acaba de llamar myMethod pero en lugar myMethod:setValue2:.

También (y podría estar fuera de base aquí), creo que técnicamente puede soltar las palabras entre dos puntos y así también usar @selector(myMethod::) pero no me cite sobre esto a menos que otros puedan confirmarlo.

+2

Eso es incorrecto. El selector es el nombre completo del método, incluido todo entre los dos puntos. 'myMethod ::' y 'myMethod: setValue2:' son selectores distintos, que se asociarían con distintas implementaciones a menos que hayas trabajado alguna magia de tiempo de ejecución. –

+0

OK. Estaba fuera de la base. – jbrennan

27

Para scheduledTimerWithTimeInterval:, el selector que pase solo puede tener un argumento. Además, su único argumento debe ser un objeto NSTimer *. En otras palabras, el selector debe tener el siguiente contenido:

- (void)timerFireMethod:(NSTimer*)theTimer 

Lo que podría hacer es almacenar los argumentos en el diccionario userInfo y llamar al selector que desea de la devolución de llamada de temporizador:

- (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]; 
} 
+2

Esto es correcto para el método específico que ha publicado anteriormente isiaatz. Si eso fue solo un ejemplo y desea saber en general cómo enviar múltiples argumentos a un selector, modifique su pregunta – h4xxr

+0

Me gusta más esta respuesta que la aceptada, ya que es más concisa. –

+1

Prefiero esto mejor también –

2

parece a un trabajo para los bloques (suponiendo que se apunta para Snow Leopard.)

-jcr

0

bloques parecer una respuesta obvia ahora ... pero hay otro idioma que era muy un lugar común en el tiempo de ejecución clásica, el decapado de sus argumentos en un único objeto:

- (void)doMyMethod:(NSDictionary *)userInfo 
{ 
    [self myMethod: [userInfo objectForKey:@"value1"] setValue2: [userInfo objectForKey:@"value2"]]; 
} 
- (void)myMethod:(NSString*)value1 setValue2:(NSString*)value2{ 

} 

ahora se puede enviar a

[self performSelector:@selector(doMyMethod:) withObject:@{@"value1":@"value1",@"value2":@"value2"}];