¿Cómo puedo retrasar una llamada al método por 1 segundo?


164

¿Hay una manera fácil de retrasar una llamada de método por 1 segundo?

Tengo un UIImageViewque reacciona en un evento táctil. Cuando se detecta el toque, algunas animaciones suceden en la aplicación. Después de un segundo, quiero llamar a otro método. En este caso, no puedo usar el animationDidStopselector.


Ciertamente, hay varias formas de hacerlo, una de ellas podría ser simplemente usar sleep () para suspender el programa / hilo durante varios milisegundos, sin embargo , creo que es posible que desee decirnos qué es exactamente lo que está tratando de lograr mediante ¿haciendo eso? Quiero decir, ¿cuál es tu problema real? La idea de retrasar una llamada al método parece ser una 'solución', una que no suena demasiado buena para ser honesto. Entonces, solo cuéntanos más sobre el escenario que tienes en mente.
ninguno

Respuestas:


254
performSelector:withObject:afterDelay:

Referencia de documento


77

¿Hay alguna forma de algo con el valor de retorno del método que se llama? ¿O necesito configurarlo para modificar el parámetro si quiero recuperar alguna información?
Gordon Gustafson el

si alguien está interesado en cómo cancelar la llamada programada: [NSObject cancelPreviousPerformRequestsWithTarget: yourTarget selector: aSelector object: anArgument];
vir us

192

También podrías usar un bloque

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
    [object method]; 
});

La mayoría de las veces querrá usar dispatch_get_main_queue, aunque si no hay una interfaz de usuario en el método, podría usar una cola global .

Editar:

Versión Swift 3:

DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
    object.method()
}

Igualmente, DispatchQueue.global().asyncAfter(...también podría ser una buena opción.


Descubrí que esta solución es más fácil que realizarSelector al mezclar directamente C y ObjC
Paul Slocum

1
Lamentablemente, dispatch_get_current_queue está en desuso desde iOS6
chrisben

3
Actualizado para usar dispatch_get_main_queue en lugar de dispatch_get_current_queue
mcfedr

2
Xcode ahora completará automáticamente esto, solo comience a escribir dispatch_aftery presione enter
mcfedr

1
Especialmente ahora que Xcode completa esto automáticamente al escribir dispatch_after, esta es realmente una forma súper sencilla de hacerlo, además de que puede transferir propiedades al método que está llamando, lo cual es genial.
Erik van der Neut

128

La mejor manera de hacerlo es:

[self performSelector:@selector(YourFunctionName) 
           withObject:(can be Self or Object from other Classes) 
           afterDelay:(Time Of Delay)];

También puede pasar nil como con el parámetro Object.

ejemplo:

[self performSelector:@selector(subscribe) withObject:self afterDelay:3.0 ];

3
¿Por qué te pasarías a ti mismo?
Eric

2
¿Y por qué pasarías una variable a un método que toma cero argumentos?
hellozimi

23

Ya hay muchas respuestas y todas son correctas. En caso de que desee usar el dispatch_after, debe buscar el fragmento que se incluye dentro de la Code Snippet Libraryparte inferior derecha (donde puede seleccionar los UIelementos).

ingrese la descripción de la imagen aquí

Entonces solo necesita llamar a este fragmento escribiendo despacho en código:

ingrese la descripción de la imagen aquí


16

Puede usar el selector de ejecución para después de que el método de retraso de 0.1 segundos se llame para que el siguiente código haga esto.

[self performSelector:@selector(InsertView)  withObject:nil afterDelay:0.1]; 

9

Tú también puedes:

[UIView animateWithDuration:1.0
                 animations:^{ self.view.alpha = 1.1; /* Some fake chages */ }
                 completion:^(BOOL finished)
{
    NSLog(@"A second lapsed.");
}];

En este caso, debe simular algunos cambios en alguna vista para que la animación funcione. Es realmente hacky, pero me encantan las cosas basadas en bloques. O finalice la respuesta de @mcfedr a continuación.


waitFor(1.0, ^
{
    NSLog(@"A second lapsed");
});

typedef void (^WaitCompletionBlock)();
void waitFor(NSTimeInterval duration, WaitCompletionBlock completion)
{
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, duration * NSEC_PER_SEC),
                   dispatch_get_main_queue(), ^
    { completion(); });
}

No estoy seguro, pero creo que la primera opción que sugiera puede tener efectos secundarios que los usuarios deben tener en cuenta, por ejemplo, bloquear la interacción del usuario en partes de la interfaz de usuario. Mi instinto es que también causaría una pérdida innecesaria de CPU u otro recurso, pero no lo he comprobado.
Bjorn Roche

8

Puedes hacerlo

[self performSelector:@selector(MethodToExecute) withObject:nil afterDelay:1.0 ];

4

Swift 2.x

let delayTime = dispatch_time(DISPATCH_TIME_NOW, Int64(1 * Double(NSEC_PER_SEC)))
 dispatch_after(delayTime, dispatch_get_main_queue()) {
 print("do some work")
}

Swift 3.x - & - Swift 4

DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
    print("do some work")
}

o pasar un escaping closure

func delay(seconds: Double, completion: @escaping()-> Void) {
    DispatchQueue.main.asyncAfter(deadline: .now() + seconds, execute: completion)
}

1

Hay una solución Swift 3 de la solución marcada:

self.perform(#selector(self.targetMethod), with: self, afterDelay: 1.0)

Y ahí está el método

@objc fileprivate func targetMethod(){

}


-34

NOTA: esto pausará todo su hilo, no solo el método.
¿Llamar a dormir / esperar / detener 1000 ms justo antes de llamar a su método?

Sleep(1000); // does nothing the next 1000 mSek

Methodcall(params); // now do the real thing

Editar: La respuesta anterior se aplica a la pregunta general "¿Cómo puedo retrasar una llamada al método por 1 segundo?", Que era la pregunta que se hizo en el momento de la respuesta (de hecho, la respuesta se dio dentro de los 7 minutos de la pregunta original: - )). No se proporcionó información sobre el idioma en ese momento, así que amablemente deje de quejarse sobre la forma correcta de usar sleep i XCode og la falta de clases ...


Solo en el hilo actual, otros hilos continuarán ejecutándose.
Marc Charbonneau

44
Geez Entiendo por qué esto fue rechazado varias veces, pero ¿quién diablos vio esto en -27 y decidió que necesitaba otro? ¿Tiene -3 o algo que no se entiende? ¿Por qué no simplemente editar la respuesta para decir "esto detendrá todo tu hilo" o algo así en lugar de rechazarlo?
Albert Renshaw

Entonces, ¿qué pasa si solo quieres pausar todo el hilo? Parece una opción válida si viene con una advertencia decente.
Departamento B

@AlbertRenshaw Estoy totalmente de acuerdo contigo. Estoy aquí y sus 35 bajas y le di mi arriba. Veo más como atacar tan mal a los usuarios de baja reputación. Nadie hará ninguna edición ni especificará nada. Hoy he visto una respuesta que realmente se ahogó. El único error que hizo esa persona es que él / ella respondió bajo una pregunta rápida con lenguaje objetivo c. Si se trata de un gran error, quiero mostrar tantas respuestas rápidas en las preguntas del objetivo c.
soorej babu
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.