iOS - ¿Cómo implementar un performSelector con múltiples argumentos y con afterDelay?


Soy un novato de iOS. Tengo un método selector de la siguiente manera -

- (void) fooFirstInput:(NSString*) first secondInput:(NSString*) second
{

}

Estoy tratando de implementar algo como esto -

[self performSelector:@selector(fooFirstInput:secondInput:) withObject:@"first" withObject:@"second" afterDelay:15.0];

Pero eso me da un error diciendo -

Instance method -performSelector:withObject:withObject:afterDelay: not found

¿Alguna idea de lo que me estoy perdiendo?

Author: Suchi, 2011-12-09

8 answers

Personalmente, creo que una solución más cercana a sus necesidades es el uso de NSInvocation.

Algo como lo siguiente hará el trabajo:

indexPath y origen de datos son dos variables de instancia definidas en el mismo método.

SEL aSelector = NSSelectorFromString(@"dropDownSelectedRow:withDataSource:");

if([dropDownDelegate respondsToSelector:aSelector]) {
    NSInvocation *inv = [NSInvocation invocationWithMethodSignature:[dropDownDelegate methodSignatureForSelector:aSelector]];
    [inv setSelector:aSelector];
    [inv setTarget:dropDownDelegate];

    [inv setArgument:&(indexPath) atIndex:2]; //arguments 0 and 1 are self and _cmd respectively, automatically set by NSInvocation
    [inv setArgument:&(dataSource) atIndex:3]; //arguments 0 and 1 are self and _cmd respectively, automatically set by NSInvocation

    [inv invoke];
}
 136
Author: valvoline,
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-10-09 08:19:30

Porque no hay tal cosa como un método [NSObject performSelector:withObject:withObject:afterDelay:].

Necesita encapsular los datos que desea enviar en algún objeto de Objetivo C (por ejemplo, un NSArray, un NSDictionary, algún tipo de objetivo C personalizado) y luego pasarlo a través del método[NSObject performSelector:withObject:afterDelay:] que es bien conocido y querido.

Por ejemplo:

NSArray * arrayOfThingsIWantToPassAlong = 
    [NSArray arrayWithObjects: @"first", @"second", nil];

[self performSelector:@selector(fooFirstInput:) 
           withObject:arrayOfThingsIWantToPassAlong  
           afterDelay:15.0];
 97
Author: Michael Dautermann,
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-12-08 23:20:51

Puede empaquetar sus parámetros en un objeto y usar un método auxiliar para llamar a su método original como Michael, y otros ahora, han sugerido.

Otra opción es dispatch_after, que tomará un bloque y lo encolará en un momento determinado.

double delayInSeconds = 15.0;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);

dispatch_after(popTime, dispatch_get_main_queue(), ^(void){

    [self fooFirstInput:first secondInput:second];

});

O, como ya ha descubierto, si no requiere el retraso, puede usar - performSelector:withObject:withObject:

 32
Author: Firoze Lafeer,
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-12-08 23:32:21

La opción más simple es modificar su método para tomar un solo parámetro que contenga ambos argumentos, como un NSArray o NSDictionary (o agregar un segundo método que tome un solo parámetro, lo descomprima y llame al primer método, y luego llame al segundo método en un retraso).

Por ejemplo, podrías tener algo como:

- (void) fooOneInput:(NSDictionary*) params {
    NSString* param1 = [params objectForKey:@"firstParam"];
    NSString* param2 = [params objectForKey:@"secondParam"];
    [self fooFirstInput:param1 secondInput:param2];
}

Y luego para llamarlo, puedes hacer:

[self performSelector:@selector(fooOneInput:) 
      withObject:[NSDictionary dictionaryWithObjectsAndKeys: @"first", @"firstParam", @"second", @"secondParam", nil] 
      afterDelay:15.0];
 8
Author: aroth,
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
2014-11-08 15:48:34
- (void) callFooWithArray: (NSArray *) inputArray
{
    [self fooFirstInput: [inputArray objectAtIndex:0] secondInput: [inputArray objectAtIndex:1]];
}


- (void) fooFirstInput:(NSString*) first secondInput:(NSString*) second
{

}

Y llámalo con:

[self performSelector:@selector(callFooWithArray) withObject:[NSArray arrayWithObjects:@"first", @"second", nil] afterDelay:15.0];
 6
Author: Mike Wallace,
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-12-08 23:21:27

Puede encontrar todos los tipos de métodos performSelector: aquí:

Http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/nsobject_Class/Reference/Reference.html

Hay un montón de variaciones, pero no hay una versión que toma varios objetos, así como un retraso. Tendrá que terminar sus argumentos en un NSArray o NSDictionary en su lugar.

- performSelector:
- performSelector:withObject:
- performSelector:withObject:withObject:
– performSelector:withObject:afterDelay:
– performSelector:withObject:afterDelay:inModes:
– performSelectorOnMainThread:withObject:waitUntilDone:
– performSelectorOnMainThread:withObject:waitUntilDone:modes:
– performSelector:onThread:withObject:waitUntilDone:
– performSelector:onThread:withObject:waitUntilDone:modes:
– performSelectorInBackground:withObject: 
 5
Author: StilesCrisis,
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-12-08 23:24:18

No me gusta la forma de NSInvocación, demasiado compleja. Vamos a mantenerlo simple y limpio:

// Assume we have these variables
id target, SEL aSelector, id parameter1, id parameter2;

// Get the method IMP, method is a function pointer here.
id (*method)(id, SEL, id, id) = (void *)[target methodForSelector:aSelector];

// IMP is just a C function, so we can call it directly.
id returnValue = method(target, aSelector, parameter1, parameter2);
 2
Author: BB9z,
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
2018-02-22 02:22:23

Acabo de hacer un poco de swizzling y necesitaba llamar al método original. Lo que hice fue hacer un protocolo y lanzar mi objeto a él. Otra forma es definir el método en una categoría, pero necesitaría supresión de una advertencia (#pragma clang diagnostic ignorado "- Wincomplete-implementation").

 1
Author: darkfader,
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
2013-03-27 09:41:26