Wie kann ich einen Methodenaufruf um 1 Sekunde verzögern?


164

Gibt es eine einfache Möglichkeit, einen Methodenaufruf um 1 Sekunde zu verzögern?

Ich habe eine UIImageView, die auf ein Berührungsereignis reagiert. Wenn die Berührung erkannt wird, werden einige Animationen in der App ausgeführt. Nach einer Sekunde möchte ich eine andere Methode aufrufen. In diesem Fall kann ich den animationDidStopSelektor nicht verwenden .


Es gibt sicherlich mehrere Möglichkeiten, dies zu tun. Eine davon könnte darin bestehen, das Programm / den Thread einfach mit sleep () für einige Millisekunden anzuhalten. Ich denke jedoch , Sie möchten uns vielleicht mitteilen, was genau Sie damit erreichen möchten das machen? Ich meine, was ist dein eigentliches Problem? Die Idee, einen Methodenaufruf zu verzögern, scheint eine „Lösung“ zu sein, die ehrlich gesagt nicht allzu gut klingt. Erzählen Sie uns einfach mehr über das Szenario, an das Sie denken.
keine

Antworten:


254
performSelector:withObject:afterDelay:

Dokumentverweis


7
Dies ist die richtige Antwort. Bitte sehen Sie auf developer.apple.com/DOCUMENTATION/Cocoa/Reference/Foundation/… :
schadet

Gibt es eine Möglichkeit zu etwas mit dem Rückgabewert der Methode, die aufgerufen wird? Oder muss ich es einrichten, um den Parameter zu ändern, wenn ich Informationen zurückerhalten möchte?
Gordon Gustafson

Wenn jemand interessiert ist, wie ein geplanter Anruf abgebrochen werden kann: [NSObject cancelPreviousPerformRequestsWithTarget: yourTarget selector: aSelector object: anArgument];
Vir uns

192

Sie können auch einen Block verwenden

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

Meistens möchten Sie dispatch_get_main_queue verwenden. Wenn die Methode jedoch keine Benutzeroberfläche enthält, können Sie eine globale Warteschlange verwenden .

Bearbeiten:

Swift 3 Version:

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

Ebenso DispatchQueue.global().asyncAfter(...könnte auch eine gute Option sein.


Diese Lösung war einfacher als performSelector, wenn gerade C und ObjC gemischt wurden
Paul Slocum

1
Leider ist dispatch_get_current_queue seit iOS6
chrisben

3
Aktualisiert, um dispatch_get_main_queue anstelle von dispatch_get_current_queue zu verwenden
mcfedr

2
Xcode wird dies nun automatisch vervollständigen. Beginnen Sie einfach mit der Eingabe dispatch_afterund drücken Sie die Eingabetaste
mcfedr

1
Besonders jetzt, wo Xcode dies beim Tippen automatisch vervollständigt dispatch_after, ist dies eine sehr einfache Möglichkeit, dies zu tun. Außerdem können Sie Eigenschaften an die Methode übergeben, die Sie aufrufen, was großartig ist.
Erik van der Neut

128

Der beste Weg ist:

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

Sie können nil auch als withObject-Parameter übergeben.

Beispiel:

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

3
Warum würdest du dich selbst an dich weitergeben?
Eric

2
Und warum sollten Sie eine Variable an eine Methode übergeben, die keine Argumente akzeptiert?
Hellozimi

23

Es gibt bereits viele Antworten und alle sind richtig. Wenn Sie das verwenden möchten, dispatch_aftersollten Sie nach dem Snippet suchen, Code Snippet Librarydas rechts unten im enthalten ist (wo Sie die UIElemente auswählen können ).

Geben Sie hier die Bildbeschreibung ein

Sie müssen dieses Snippet also nur aufrufen, indem Sie den Versand in Code schreiben :

Geben Sie hier die Bildbeschreibung ein


16

Sie können den Perform-Selektor verwenden, nachdem die 0,1-Sekunden-Verzögerungsmethode den folgenden Code aufgerufen hat, um dies zu tun.

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

9

Du kannst auch:

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

In diesem Fall müssen Sie einige Änderungen an einer Ansicht vortäuschen, damit die Animation funktioniert. Es ist zwar hackig, aber ich liebe das blockbasierte Zeug. Oder schließen Sie die Antwort von @mcfedr unten ab.


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

Ich bin mir nicht sicher, aber ich denke, die erste Option, die Sie vorschlagen, kann Nebenwirkungen haben, die Benutzer beachten sollten, z. B. das Blockieren der Benutzerinteraktion auf Teilen der Benutzeroberfläche. Mein Instinkt ist, dass es auch unnötigen CPU- oder anderen Ressourcenverbrauch verursachen würde, aber ich habe es nicht überprüft.
Björn Roche

8

Du kannst das

[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")
}

oder pass a escaping closure

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

1

Es gibt eine Swift 3-Lösung aus der überprüften Lösung:

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

Und da ist die Methode

@objc fileprivate func targetMethod(){

}


-34

HINWEIS: Dadurch wird Ihr gesamter Thread angehalten, nicht nur die eine Methode.
Rufen Sie 1000 ms lang an, um zu schlafen / warten / anhalten, bevor Sie Ihre Methode aufrufen?

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

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

Bearbeiten: Die obige Antwort gilt für die allgemeine Frage "Wie kann ich einen Methodenaufruf um 1 Sekunde verzögern?", Die zum Zeitpunkt der Antwort gestellt wurde (tatsächlich wurde die Antwort innerhalb von 7 Minuten nach der ursprünglichen Frage gegeben: - )). Zu dieser Zeit wurden keine Informationen über die Sprache gegeben. Hören Sie also bitte auf, sich über die richtige Art und Weise der Verwendung von Schlaf zu beschweren.


Nur im aktuellen Thread werden andere Threads weiterhin ausgeführt.
Marc Charbonneau

4
Meine Güte. Ich verstehe, warum dies ein paar Mal abgelehnt wurde, aber wer zum Teufel hat das bei -27 gesehen und entschieden, dass es ein anderes braucht? Vermittelt -3 oder etwas nicht den Punkt. Warum bearbeiten Sie nicht einfach die Antwort, um zu sagen "Dies wird Ihren gesamten Thread anhalten" oder etwas anderes, anstatt ihn herunterzustimmen?
Albert Renshaw

Was ist, wenn Sie nur den gesamten Thread anhalten möchten? Scheint eine gültige Option zu sein, wenn eine anständige Warnung vorliegt.
Departamento B

@ AlbertRenshaw Ich stimme dir vollkommen zu. Ich bin hier und seine 35 Tiefen und ich gab ihm mein Auf. Ich sehe eher so, als würde ich so schlecht gegen die wenig bekannten Benutzer angreifen. Niemand wird etwas bearbeiten oder spezifizieren. Ich habe heute eine Antwort gesehen, dass die wirklich ertrunken sind. Der einzige Fehler, den diese Person gemacht hat, ist die Beantwortung unter einer schnellen Frage mit objektiver Sprache. Wenn es ein großer Fehler ist, möchte ich unter objektiven Fragen so viele schnelle Antworten zeigen.
Soorej Babu
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.