2009-06-19 18 views
135

En MyClass.m, he definidoObjective-C: Llamada selectores con múltiples argumentos

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

y la declaración correspondiente en MyClass.h. Más tarde Quiero llamar

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

en MyClass.m pero me da un error similar al * Terminación de aplicación debido a excepción no detectada 'NSInvalidArgumentException', razón: '* - [MiClase myTest: withAtring:]: selector no reconocido enviado a la instancia 0xe421f0 '

Intenté un caso más simple con un selector que no tomaba ningún argumento que imprimiera una cadena a la consola y que funcionó bien. ¿Qué pasa con el código y cómo puedo solucionarlo? Gracias.

+4

Tu publicación pregunta por 'argumentos múltiples', pero solo utilizas una. Ahora tengo curiosidad acerca de cómo alguien LO HARÍA con múltiples argumentos, además de envolverlos en una matriz/dict/lo que sea. – RonLugge

Respuesta

130

Su firma del método es:

- (void) myTest:(NSString *) 

withAString pasa a ser el parámetro (el nombre es engañoso, parece que es parte de la firma del selector).

Si se llama a la función de esta manera:

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

Se trabajará.

Pero, como han sugerido los otros carteles, es posible que desee cambiar el nombre del método:

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

Y llama:

[self performSelector:@selector(myTestWithAString:) withObject:myString]; 
+1

Gracias! Corrección secundaria. La "t" en "mytest:" debe estar en mayúscula en "T". self performSelector: @selector (mytest :) withObject: myString]; – Stu

+0

Gracias, actualicé mi publicación :) –

+1

Ahora que veo personas que se han beneficiado de esta respuesta, he revisado mi respuesta; Sugeriría que la llamada sea simplemente: - (void) testWithString: (NSString *) aString; –

2

piensan que la clase debe ser definida como:

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

sólo tiene un único parámetro por lo que sólo debe tener una sola:

Es posible que desee considerar el uso de% @ in también su NSLog - es solo un buen hábito para entrar - luego escribirá cualquier objeto - no solo cadenas.

3

La firma de su método no tiene sentido, ¿está seguro de que no es un error tipográfico? No tengo claro cómo se está compilando, aunque tal vez recibas advertencias que ignoras.

¿Cuántos parámetros espera que tome este método?

+0

Disculpa que estés escribiendo. Lo escribí e intenté simplificarlo en lugar de copiar y pegar mi código, pero cometí un error en el proceso. Estoy esperando que este método tome un parámetro; la cadena que me gustaría imprimir – Stu

297

En Objective-C, la firma de un selector consta de:

  1. El nombre del método (en este caso sería 'myTest') (obligatorio)
  2. A ':' (dos puntos) siguiendo el nombre del método si el método tiene una entrada.
  3. Un nombre y ':' para cada entrada adicional.

selectores tienen ningún conocimiento de:

  1. Los tipos de entrada
  2. El método de tipo de retorno.

Aquí hay una implementación de la clase, donde el método performMethodsViaSelectors realiza los otros métodos de clase por medio de selectores:

@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 

El método que desea crear un selector para tiene una sola entrada, por lo que se crearía un selector para que así sea:

SEL myTestSelector = @selector(myTest:); 
+3

Buena respuesta. Para aclarar un poco, el nombre del selector DEBE tener al menos una parte, que puede o no tomar un parámetro; si lo hace, debe tener dos puntos. Los nombres de selector con dos o más partes DEBEN tener dos puntos después de CADA parte; no es legal tener un selector de la forma "-useFoo: andBar: toDoSomething". –

+0

gracias por esto. He estado luchando con esto por un tiempo, ¡me alegro de la ayuda! –

+0

¿qué tal los parámetros de entrada son números enteros? ¿Qué hacer en este caso? –

7

Su código tiene dos problemas. Uno fue identificado y respondido, pero el otro no. La primera era que a su selector le faltaba el nombre de su parámetro. Sin embargo, incluso cuando arregle eso, la línea aún generará una excepción, suponiendo que la firma de su método revisado aún incluya más de un argumento. Digamos que su método revisado se declara como:

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

Creación de selectores de métodos que toman múltiples argumentos es perfectamente válido (por ejemplo @selector (myTestWithString: comparedto :)). Sin embargo, el método performSelector solo le permite pasar un valor a myTest, que desafortunadamente tiene más de un parámetro. Se equivocará y le dirá que no proporcionó suficientes valores.

Siempre se puede volver a definir su método para tomar una colección ya que es único parámetro:

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

Sin embargo, no es una solución más elegante (que no requiere refactorización). La respuesta es usar NSInvocation, junto con sus métodos setArgument:atIndex: y invoke.

He escrito an article, including a code example, si desea más detalles. El enfoque está en enhebrar, pero los conceptos básicos aún se aplican.

Buena suerte!

13

@Shane Arney

performSelector:withObject:withObject: 

También podría querer mencionar que este método es sólo para pasar un máximo de 2 argumentos, y no puede ser retrasado. (Como performSelector:withObject:afterDelay:)

un poco raro que Apple sólo admite 2 objetos que se van a enviar y ni que sea más genérico

+2

Gracias por la información. No pude hacer que el retraso funcionara y ahora sé por qué. Para tu información, para pasar el límite de dos objetos, pasé una matriz y luego la usé en el método. – JScarry

0

usuarios de iOS también esperan autocapitalization:.. En un campo de texto estándar, la primera letra una frase en un idioma entre mayúsculas y minúsculas es automáticamente en mayúsculas

puede decidir si aplica o no tales características;. no hay API dedicada para cualquiera de las funciones que acabamos de mencionar, por lo proporcionándoles es una ventaja competitiva .

El documento de Apple dice que no hay una API disponible para esta característica y otra característica esperada en un teclado personalizado. entonces necesitas encontrar tu propia lógica para implementar esto.

Cuestiones relacionadas