cómo llamar a un método de múltiples argumentos con retraso


Estoy tratando de llamar a un método después de algún retraso.

Sé que hay una solución para eso:

[self performSelector:@selector(myMethod) withObject:nil afterDelay:delay];

Vi esta pregunta y Documentación

Pero mi pregunta es: ¿Cómo puedo llamar a un método que toma dos parámetros??

Por ejemplo:

- (void) MoveSomethigFrom:(id)from To:(id)to;

Cómo llamaría a este método con retraso, usando performSelector:withObject:afterDelay:

Gracias

Author: Community, 2012-03-09

6 answers

Utilice dispatch_after:

double delayInSeconds = 2.0;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
    //code to be executed on the main queue after delay
    [self MoveSomethingFrom:from To:to];
});

EDITAR 2015: Para Swift, recomiendo usar este pequeño método auxiliar: dispatch_after - GCD en swift?

 112
Author: Martin Ullrich,
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
2017-05-23 12:00:35

También puede implementar el método en la categoría NSObject usando el objeto NSInvocation (funciona en todas las versiones de iOS). Supongo que debería ser algo como esto:

@interface NSObject(DelayedPerform)

- (void)performSelector:(SEL)aSelector withObject:(id)argument0 withObject:(id)argument1  afterDelay:(NSTimeInterval)delay {

  NSMethodSignature *signature = [self methodSignatureForSelector:aSelector];

  NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
  [invocation setTarget:self];
  [invocation setSelector:aSelector];
  [invocation setArgument:&argument0 atIndex:2];
  [invocation setArgument:&argument1 atIndex:3];

  [invocation performSelector:@selector(invoke) withObject:nil afterDelay:delay];

}

@end
 7
Author: Eldar Markov,
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-03-09 18:39:11

Otras ideas:

1) Usted podría utilizar NSInvocations:

+ (NSInvocation *)invocationWithMethodSignature:(NSMethodSignature *)signature
(>> véase La respuesta de Eldar Markov)

Documentación:
https://developer.apple.com/library/ios/#documentation/Cocoa/Reference/Foundation/Classes/NSInvocation_Class/Reference/Reference.html

2) Podría usar un método de ayuda..

[self performSelector:@selector(helperMethod) withObject:nil afterDelay:delay];

- (void) helperMethod
{
    // of course x1 and x2 have to be safed somewhere else
    [object moveSomethigFrom: x1 to: x2];
}

3) Se puede usar un array o un diccionario como parámetro..

NSArray* array = [NSArray arrayWithObjects: x1, x2, nil];
[self performSelector:@selector(handleArray:) withObject:array afterDelay:delay];

- (void) handleArray: (NSArray*) array
{
    [object moveSomethigFrom: [array objectAtIndex: 0] to: [array objectAtIndex: 1]];
}
 6
Author: calimarkus,
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
2017-05-23 11:54:09

Swift:

    let delayInSeconds = 3.0;
    let delay = delayInSeconds * Double(NSEC_PER_SEC)
    let popTime = dispatch_time(DISPATCH_TIME_NOW, Int64(delay));
    dispatch_after(popTime, dispatch_get_main_queue(), {
        // DO SOMETHING AFTER 3 sec
    });
 2
Author: Alexander Volkov,
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-10-25 11:23:54

Aquí es cómo puede activar un bloque después de un retraso en Swift:

runThisAfterDelay(seconds: 5) { () -> () in
    print("Prints this 5 seconds later in main queue")
    //Or perform your selector here
}

/// EZSwiftExtensions
func runThisAfterDelay(seconds seconds: Double, after: () -> ()) {
    let time = dispatch_time(DISPATCH_TIME_NOW, Int64(seconds * Double(NSEC_PER_SEC)))
    dispatch_after(time, dispatch_get_main_queue(), after)
}

El número de argumentos realmente no importa.

Se incluye como una función estándar en mi repositorio: https://github.com/goktugyil/EZSwiftExtensions

 1
Author: Esqarrouth,
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
2015-12-01 22:28:37

Todos estos funcionarán, pero son mucho más complejos de lo que se necesita.

Diseñe el método a llamar con un argumento NSDictionary. Pon los objetos que necesites.

Si desea que el método sea accesible también por otros medios, llame en su lugar a un método que 'desenvuelva' el diccionario y llame al método deseado con parámetros explícitos.

 0
Author: tooluser,
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-05-23 04:01:26