¿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.

Gracias
fuente
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

Jim
fuente
77
Esta es la respuesta correcta. Consulte developer.apple.com/DOCUMENTATION/Cocoa/Reference/Foundation/… :
perjudica
¿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.

mcfedr
fuente
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 ];
Milianoo
fuente
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í

Alex Cio
fuente
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]; 
Nimit Parekh
fuente
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(); });
}
Geri Borbás
fuente
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 ];
Nitesh
fuente
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)
}
Salman Ghumsani
fuente
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(){

}
Kevin ABRIOUX
fuente
0

Uso en Swift 3

perform(<Selector>, with: <object>, afterDelay: <Time in Seconds>)
Sujeet Shrivastav
fuente
-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 ...

Tom Arleth
fuente
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