objective c - Objective-C: llamar a selectores con mĂșltiples argumentos
(7)
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 al de * Terminación de la aplicación debido a una 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.
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 idioma que distingue entre mayúsculas y minúsculas se escribe automáticamente en mayúscula.
Usted puede decidir si implementar o no tales características; no hay una API dedicada para ninguna de las funciones que acabamos de enumerar, por lo que 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.
@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.
En Objective-C, la firma de un selector consiste en:
- El nombre del método (en este caso sería ''myTest'') (obligatorio)
- A '':'' (dos puntos) siguiendo el nombre del método si el método tiene una entrada.
- Un nombre y '':'' para cada entrada adicional.
Los selectores no tienen conocimiento de:
- Los tipos de entrada
- 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:);
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?
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.
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];
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 ;
La creación de selectores para métodos que toman múltiples argumentos es perfectamente válida (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, incluido un ejemplo de código , si desea más detalles. El enfoque está en enhebrar, pero los conceptos básicos aún se aplican.
¡Buena suerte!