Comment puis-je retarder un appel de méthode d'une seconde?


164

Existe-t-il un moyen simple de retarder un appel de méthode d'une seconde?

J'ai un UIImageViewqui réagit sur un événement tactile. Lorsque le toucher est détecté, certaines animations se produisent dans l'application. Au bout d'une seconde, je veux appeler une autre méthode. Dans ce cas, je ne peux pas utiliser le animationDidStopsélecteur.


Il y a certainement plusieurs façons de le faire, l'une d'entre elles pourrait être simplement d'utiliser sleep () pour suspendre le programme / thread pendant un certain nombre de millisecondes, mais je pense que vous voudrez peut-être nous dire ce que vous essayez d'accomplir exactement en Faisant cela? Je veux dire, quel est votre problème réel? L'idée de retarder un appel de méthode semble être une «solution» qui ne semble pas trop belle pour être honnête. Alors, dites-nous simplement plus sur le scénario que vous avez en tête.
aucun

Réponses:


254
performSelector:withObject:afterDelay:

Référence de document


7
C'est la bonne réponse. Veuillez voir developer.apple.com/DOCUMENTATION/Cocoa/Reference/Foundation/… :
nuit

Y a-t-il un moyen de quelque chose avec la valeur de retour de la méthode qui est appelée? Ou dois-je le configurer pour modifier le paramètre si je veux en récupérer des informations?
Gordon Gustafson

si quelqu'un est intéressé par la manière d'annuler l'appel programmé: [NSObject cancelPreviousPerformRequestsWithTarget: yourTarget selector: aSelector object: anArgument];
vir us

192

Vous pouvez également utiliser un bloc

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

La plupart du temps, vous souhaiterez utiliser dispatch_get_main_queue, bien que s'il n'y a pas d'interface utilisateur dans la méthode, vous pouvez utiliser une file d'attente globale .

Éditer:

Version Swift 3:

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

De même, cela DispatchQueue.global().asyncAfter(...pourrait également être une bonne option.


J'ai trouvé cette solution plus facile que performSelector lors du mélange de C et ObjC
Paul Slocum

1
Malheureusement, dispatch_get_current_queue est obsolète depuis iOS6
chrisben

3
Mise à jour pour utiliser dispatch_get_main_queue au lieu de dispatch_get_current_queue
mcfedr

2
Xcode va maintenant compléter automatiquement cela, commencez simplement à taper dispatch_afteret appuyez sur Entrée
mcfedr

1
Surtout que maintenant Xcode le complète automatiquement lors de la saisie dispatch_after, c'est vraiment un moyen très simple de le faire, de plus vous pouvez transmettre des propriétés à la méthode que vous appelez, ce qui est génial.
Erik van der Neut

128

La meilleure façon de procéder est:

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

vous pouvez également passer nil comme paramètre withObject.

exemple :

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

3
Pourquoi vous passeriez-vous à vous-même?
Eric

2
Et pourquoi passeriez-vous une variable à une méthode qui ne prend aucun argument?
hellozimi

23

Il y a déjà beaucoup de réponses et elles sont toutes correctes. Si vous souhaitez utiliser le, dispatch_aftervous devriez rechercher l'extrait de code qui est inclus dans le Code Snippet Libraryen bas à droite (où vous pouvez sélectionner les UIéléments).

entrez la description de l'image ici

Il vous suffit donc d'appeler cet extrait de code en écrivant dispatch dans le code:

entrez la description de l'image ici


16

Vous pouvez utiliser le sélecteur d'exécution après que la méthode de délai de 0,1 s soit appelée pour que le code suivant effectue cette opération.

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

9

Vous pouvez également:

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

Dans ce cas, vous devez simuler certaines modifications de certaines vues pour que l'animation fonctionne. C'est vraiment hacky, mais j'adore les trucs basés sur des blocs. Ou résumez la réponse @mcfedr ci-dessous.


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(); });
}

Pas sûr, mais je pense que la première option que vous suggérez peut avoir des effets secondaires dont les utilisateurs doivent être conscients, par exemple le blocage de l'interaction de l'utilisateur sur certaines parties de l'interface utilisateur. Mon instinct est que cela entraînerait également une perte inutile de CPU ou d'autres ressources, mais je n'ai pas vérifié.
Bjorn Roche

8

Tu peux le faire

[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 - et - Swift 4

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

ou passer un escaping closure

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

1

Il existe une solution Swift 3 de la solution vérifiée:

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

Et il y a la méthode

@objc fileprivate func targetMethod(){

}


-34

REMARQUE: cela mettra en pause l'ensemble de votre thread, pas seulement la méthode unique.
Passer un appel pour dormir / attendre / arrêter pendant 1000 ms juste avant d'appeler votre méthode?

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

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

Edit: La réponse ci-dessus s'applique à la question générale "Comment puis-je retarder un appel de méthode d'une seconde?", Qui était la question posée au moment de la réponse (en fait, la réponse a été donnée dans les 7 minutes suivant la question d'origine: - )). Aucune information n'a été donnée sur la langue à ce moment-là, alors arrêtez de vous plaindre de la bonne façon d'utiliser sleep i XCode og le manque de cours ...


Uniquement dans le thread actuel, les autres threads continueront à s'exécuter.
Marc Charbonneau

4
Bon sang. Je comprends pourquoi cela a été rejeté à plusieurs reprises, mais qui diable a vu cela à -27 et a décidé qu'il en fallait un autre? Est-ce que -3 ou quelque chose ne fait pas passer le message. Pourquoi ne pas simplement modifier la réponse pour dire "cela mettra en pause tout votre fil" ou quelque chose au lieu de voter contre les gens?
Albert Renshaw

Alors que faire si vous voulez juste mettre en pause tout le fil? Semble être une option valable si elle est accompagnée d'un avertissement décent.
Departamento B

@AlbertRenshaw Je suis totalement d'accord avec vous. Je suis ici et ses 35 bas et je lui ai donné ma place. Je vois plus comme attaquer si mal les utilisateurs peu réputés. Personne ne fera de modification ni ne précisera quoi que ce soit. J'ai vu une réponse aujourd'hui que le s'est vraiment noyé. La seule erreur que cette personne a faite est de répondre sous une question rapide avec un langage objectif. Si c'est une énorme erreur, je veux montrer autant de réponses rapides sous des questions objectives c.
soorej babu le
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.