Objective-C: Llamar a selectores con múltiples argumentos


En MyClass.m, he definido

- (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 sale un error similar a * Terminación de la aplicación debido a la excepción no capturada 'NSInvalidArgumentException', razón: '* -[MyClass MyTest: withAtring:]: selector no reconocido enviado a la instancia 0xe421f0 '

Probé un caso más simple con un selector que no tomaba argumentos que imprimieran una cadena a la consola y que funcionaba bien. ¿Qué es mal con el código y cómo puedo arreglarlo? Gracias.

Author: Stu, 2009-06-19

7 answers

Su firma de 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 llama a la función de esta manera:

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

Funcionará.

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

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

Y llame:

[self performSelector:@selector(myTestWithAString:) withObject:myString];
 133
Author: Lyndsey Ferguson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-03-15 15:52:16

En Objective-C, la firma de un selector consiste en:

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

Los selectores no tienen conocimiento de:

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

Aquí hay una implementación de clase donde el método performMethodsViaSelectors realiza 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 para el que desea crear un selector tiene una sola entrada, por lo que crearía un selector para él de la siguiente manera:

SEL myTestSelector = @selector(myTest:);
 300
Author: Shane Arney,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-07-07 20:20:48

@Shane Arney

performSelector:withObject:withObject:

Es posible que también desee mencionar que este método es solo para pasar un máximo de 2 argumentos, y no se puede retrasar. (como performSelector:withObject:afterDelay:).

Un poco raro que Apple solo soporta 2 objetos para ser enviados y no lo hizo más genérico.

 13
Author: Lirik,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-11-05 13:10:38

Su código tiene dos problemas. Una fue identificada y respondida, pero la otra no. La primera fue que a tu 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 su firma de método revisada aún incluya más de un argumento. Digamos que su método revisado se declara como:

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

Crear 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 producirá un error y le dirá que no suministró suficientes valores.

Siempre puede redefinir su método para tomar una colección, ya que es el único parámetro:

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

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

He escrito un artículo, incluyendo un ejemplo de código, si quieres más detalles. El foco está en enhebrar, pero los fundamentos todavía se aplican.

¡Buena suerte!

 7
Author: Zack,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-07-18 15:19:26

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 usted está recibiendo advertencias que usted está ignorando?

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

 3
Author: Rob Napier,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-06-19 14:24:29

Piensa que la clase debe definirse como:

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

Solo tienes un solo parámetro por lo que solo debes tener un solo:

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

 2
Author: Grouchal,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-06-19 14:23:52

Los usuarios de IOS también esperan autocapitalización: En un campo de texto estándar, la primera letra de una oración en un lenguaje sensible a mayúsculas y minúsculas es automáticamente en mayúscula.

Usted puede decidir si implementar o no tales características; no hay API dedicada para cualquiera de las características que acabamos de enumerar, por lo que proporcionarlas es una ventaja competitiva.

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

 0
Author: Kannan Prasad,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-01-12 05:43:07