Pregunta 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 apropiada en MyClass.h. Más tarde quiero llamar

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

en MyClass.m pero obtengo un error similar a * Aplicación de finalización debido a excepción no detectada 'NSInvalidArgumentException', razón: '* - [MyClass 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.


136
2018-06-19 14:19


origen


Respuestas:


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

133
2018-06-19 16:19



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

  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.

Los selectores no tienen conocimiento de:

  1. Los tipos de entrada
  2. El tipo de devolución del método.

Aquí hay una implementación de 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 para el que desea crear un selector tiene una sola entrada, por lo que debería crear un selector para él de esta manera:

SEL myTestSelector = @selector(myTest:);

298
2018-06-19 17:15



@Shane Arney

performSelector:withObject:withObject:

También es posible que 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:).

Es un poco raro que Apple solo soporte 2 objetos para enviar y no lo haga más genérico.


13
2017-11-05 13:10



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

Crear selectores para métodos que toman múltiples argumentos es perfectamente válido (por ejemplo, @selector (myTestWithString: comparisonTo :)). 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 puedes redefinir tu método para tomar una colección ya que es solo un 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 enfoque está en enhebrar, pero los conceptos básicos aún se aplican.

¡Buena suerte!


7
2017-07-18 15:19



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?


3
2018-06-19 14:24



Piensa que la clase debería definirse como:

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

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

También es posible que desee considerar el uso de% @ en su NSLog, es solo un buen hábito para ingresar, luego escribirá cualquier objeto, no solo cadenas.


2
2018-06-19 14:23



Los usuarios de iOS también esperan la 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úsculas.

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

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


0
2018-01-12 05:43