2010-04-26 10 views
27

Parece que debería haber una manera fácil de llamar a un selector con algunos argumentos cuando todo lo que tiene es un objeto SEL. Parece que no puedo encontrar la sintaxis correcta.SEL performSelector and arguments

-(MyClass*) init: (SEL)sel owner:(NSObject*) parent 
{ 
    int i =10; 
    [parent performSelector:sel:i ]; 
} 

Respuesta

74

Eche un vistazo a la documentación de NSObject. En este caso:

[parent performSelector:sel withObject:[NSNumber numberWithInt:i]]; 

(tenga en cuenta que este método es en realidad aparece en la documentación NSObject protocol). Desde -[NSObject performSelector:withObject:] requiere un argumento objeto, tendrá que escribir un envoltorio en la clase de padres como

-(void)myMethodForNumber:(NSNumber*)number { 
    [self myMethod:[number intValue]]; 
} 

a desempacar el NSNumber.

Si realmente desea invocar un método que toma argumentos que no sean objeto directamente (por ejemplo, usted no tiene control de la fuente y destinatario de la llamada no desea agregar una categoría), puede utilizar NSInvocation:

NSInvocation *inv = [NSInvocation invocationWithMethodSignature:[parent methodSignatureForSelector:sel]]; 
[inv setSelector:sel]; 
[inv setTarget:parent]; 
[inv setArgument:&i atIndex:2]; //arguments 0 and 1 are self and _cmd respectively, automatically set by NSInvocation 
[inv invoke]; 

en una nota, el método se parece a un método init, pero no sigue el patrón de inicialización correcta para Objective-C. Debe llamar al inicializador de superclases y debe probar el resultado de nil de esa llamada y debe regresar por su cuenta desde el método de inicialización. En todos los casos, sus métodos de inicializador de Objective-C debe ser similar:

-(id)myInitMethod { 
    self = [super init]; 
    if(self != nil) { 
     //perform initialization of self 
    } 

    return self; 
} 

Su método (si se trata de un método init) tendría el siguiente aspecto:

-(id) init: (SEL)sel owner:(NSObject*) parent 
{ 
    self = [super init]; 
    if(self != nil) { 
     int i = 10; 
     NSInvocation *inv = [NSInvocation invocationWithMethodSignature:[parent methodSignatureForSelector:sel]]; 
     [inv setSelector:sel]; 
     [inv setTarget:parent]; 
     [inv setArgument:&i atIndex:2]; //arguments 0 and 1 are self and _cmd respectively, automatically set by NSInvocation 
     [inv invoke]; 
    } 

    return self; 
} 

Para ser más Objective-C estilísticamente, Cambiaría el nombre del inicializador -(id)initWithSelector:owner: también.

+0

gracias, esto va más allá. Supuse que podría necesitar usar NSInvocation pero no estaba seguro. Gran respuesta. – madmik3

+0

Como comentario adicional, incluso si no tiene control sobre el destinatario, aún podría escribir un método de contenedor utilizando una categoría en esa clase para desempaquetar el objeto en el tipo primitivo. –

+0

Buen punto, Ed. –

1

Para métodos que toman una o dos objetos de tipo id como argumentos, puede utilizar:

[parent performSelector:sel withObject:argument1]; 

o

[parent performSelector:sel withObject:argument1 withObject:argument2]; 

Para los métodos con otros tipos de argumentos, cree una NSInvocation que puede encapsular llamadas a métodos arbitrarios.

+0

Asegúrese de cuantificar la firma exacta del método, p. NSSelectorFromFromString (methodWithArg1: arg2 :) – stephen

2

Quiere usar performSelector:withObject: La parte difícil es convertir el int en un objeto NSObject. No puede usar performSelector con mensajes que toman los parámetros int, sino que debe tomar un id.

Desde el NSObject Protocol Reference:

aSelector debe identificar un método que toma un solo argumento de tipo ID. Para los métodos con otros tipos de argumentos y valores devueltos, use NSInvocation.

Una vez que se hizo ese cambio, que puede hacer:

id arg = [NSNumber numberWithInt:10];  
[parent performSelector:sel withObject:arg]; 
1

que puede utilizar:

- (id)performSelector:(SEL)aSelector withObject:(id)anObject 
- (id)performSelector:(SEL)aSelector withObject:(id)anObject withObject:(id)anotherObject 

O si es necesario utilizar el método se usa más complejo NSInvocation clase

11

lo que dijo Barry Wark es genial ... acabo de modificar la discusión para los programadores perezosos

-(void)myMethodWith:(int)number andBOOL:(BOOL) someBool andStr:(NSString *)str{ 
    NSLog(@"%d %d %@",number,someBool,str); 
} 

-(void) testMethod{ 
    SEL sel = @selector(myMethodWith:andBOOL:andStr:); 
    int i = 10; 
    BOOL bol = YES; 
    NSString *str = @"hey baby !"; 
    NSInvocation *inv = [NSInvocation invocationWithMethodSignature:[self methodSignatureForSelector:sel]]; 
    [inv setSelector:sel]; 
    [inv setTarget:self]; 
    [inv setArgument:&i atIndex:2]; //arguments 0 and 1 are self and _cmd respectively, automatically set by NSInvocation 
    [inv setArgument:&bol atIndex:3]; 
    [inv setArgument:&str atIndex:4]; 
    [inv invoke]; 
} 
Cuestiones relacionadas