SEL performSelector y argumentos


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. No encuentro la sintaxis correcta.

-(MyClass*) init: (SEL)sel owner:(NSObject*) parent
{
   int i =10;
   [parent performSelector:sel:i  ];
}
Author: Keavon, 2010-04-26

5 answers

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

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

(tenga en cuenta que este método en realidad se enumeran en el NSObject protocol documentation). Dado que -[NSObject performSelector:withObject:] requiere un argumento objeto, tendrá que escribir un wrapper en la clase padre como

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

Para descomprimir el NSNumber.

Si realmente desea invocar un método que toma argumentos no objeto directamente (por ejemplo, no tiene control de la fuente de llamada y no desea agregar un 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 al margen, su método se parece a un método init, pero no sigue el patrón de inicialización correcto para Objective-C. Necesita llamar al inicializador de superclases, y necesita probar un resultado nil de esa llamada y debe devolver self desde el método inicializador. En todos los casos, los métodos del inicializador Objective-C deberían tener el siguiente aspecto:

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

    return self;
}

Su método (si es un método init) entonces se vería como:

-(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 Objetivo-C estilísticamente, cambiaría el nombre del inicializador -(id)initWithSelector:owner: también.

 76
Author: Barry Wark,
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
2010-12-28 19:30:50

Lo que Barry Wark dijo es genial.. acabo de modificar la discusión para 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];
}
 12
Author: yunas,
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-02-02 08:06:02

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

De la Referencia del Protocolo NSObject :

ASelector debe identificar un método que toma un solo argumento de tipo id. Para métodos con otros tipos de argumentos y valores de retorno, use NSInvocation.

Una vez hecho ese cambio, puedes hacer:

id arg = [NSNumber numberWithInt:10];    
[parent performSelector:sel withObject:arg];
 3
Author: Frank Krueger,
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
2010-04-26 19:22:01

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

[parent performSelector:sel withObject:argument1];

O

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

Para métodos con otros tipos de argumentos, cree un NSInvocation que pueda encapsular llamadas arbitrarias a métodos.

 1
Author: Ole Begemann,
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
2010-04-26 19:20:21

Puedes usar:

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

O si necesita usar un método más complejo, use NSInvocation class

 1
Author: Skie,
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
2010-04-26 19:22:47