Jak mogę opóźnić wywołanie metody o 1 sekundę?


164

Czy istnieje łatwy sposób opóźnienia wywołania metody o 1 sekundę?

Mam taki, UIImageViewktóry reaguje na zdarzenie dotykowe. Po wykryciu dotyku w aplikacji pojawiają się animacje. Po sekundzie chcę wywołać inną metodę. W tym przypadku nie mogę użyć animationDidStopselektora.


Z pewnością jest na to kilka sposobów, jednym z nich może być po prostu użycie funkcji sleep () do zawieszenia programu / wątku na kilka milisekund, jednak myślę, że możesz chcieć nam powiedzieć, co dokładnie próbujesz osiągnąć, robiąc to? To znaczy, jaki jest twój rzeczywisty problem? Pomysł opóźnienia wywołania metody wydaje się być „rozwiązaniem”, które szczerze mówiąc nie brzmi zbyt dobrze. Po prostu powiedz nam więcej o scenariuszu, o którym myślisz.
brak

Odpowiedzi:


254
performSelector:withObject:afterDelay:

Odnośnik do dokumentu



Czy istnieje sposób na coś ze zwracaną wartością wywoływanej metody? Czy też muszę go skonfigurować, aby zmodyfikować parametr, jeśli chcę odzyskać z niego jakieś informacje?
Gordon Gustafson

jeśli ktoś jest zainteresowany, jak anulować zaplanowane połączenie: [NSObject cancelPreviousPerformRequestsWithTarget: selektor yourTarget: aSelector object: anArgument];
vir nas

192

Możesz także użyć bloku

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

W większości przypadków będziesz chciał użyć dispatch_get_main_queue, chociaż jeśli nie ma interfejsu użytkownika w metodzie, możesz użyć globalnej kolejki .

Edytować:

Wersja Swift 3:

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

Równie dobrze DispatchQueue.global().asyncAfter(...może to być również dobra opcja.


Okazało się, że to rozwiązanie jest łatwiejsze niż performSelector podczas mieszania prostego C i ObjC
Paul Slocum

1
Niestety dispatch_get_current_queue jest przestarzały od iOS6
chrisben

3
Zaktualizowano, aby używać dispatch_get_main_queue zamiast dispatch_get_current_queue
mcfedr

2
Xcode automatycznie to uzupełni, po prostu zacznij pisać dispatch_afteri naciśnij Enter
mcfedr

1
Zwłaszcza teraz Xcode automatycznie uzupełnia to podczas pisania dispatch_after, jest to naprawdę bardzo prosty sposób, a ponadto możesz przekazać właściwości do wywoływanej metody, co jest świetne.
Erik van der Neut

128

Najlepszym sposobem jest:

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

możesz również przekazać nil jako parametr withObject.

przykład:

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

3
Dlaczego miałbyś oddawać siebie samego?
Eric,

2
A dlaczego miałbyś przekazywać zmienną do metod, które nie przyjmują żadnych argumentów?
hellozimi

23

Odpowiedzi jest już wiele i wszystkie są poprawne. Jeśli chcesz użyć tego dispatch_after, powinieneś poszukać fragmentu, który znajduje się Code Snippet Libraryw prawym dolnym rogu (gdzie możesz wybrać UIelementy).

wprowadź opis obrazu tutaj

Wystarczy więc wywołać ten fragment kodu, pisząc wiadomość w kodzie:

wprowadź opis obrazu tutaj


16

Możesz użyć selektora wykonania po wywołaniu metody opóźnienia 0,1 sekundy dla tego następującego kodu, aby to zrobić.

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

9

Możesz także:

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

W tym przypadku musisz sfałszować pewne zmiany w niektórych widokach, aby animacja działała. Rzeczywiście jest to hacky, ale uwielbiam rzeczy oparte na blokach. Lub podsumuj odpowiedź @mcfedr poniżej.


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

Nie jestem pewien, ale myślę, że pierwsza sugerowana opcja może mieć skutki uboczne, o których użytkownicy powinni wiedzieć, np. Blokowanie interakcji użytkownika z częściami interfejsu użytkownika. Instynkt podpowiada mi, że spowodowałoby to również niepotrzebne zużycie procesora lub innych zasobów, ale nie sprawdziłem.
Bjorn Roche

8

Możesz to zrobić

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

lub przejść escaping closure

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

1

Ze sprawdzonego rozwiązania jest rozwiązanie Swift 3:

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

Jest metoda

@objc fileprivate func targetMethod(){

}


-34

UWAGA: spowoduje to wstrzymanie całego wątku, a nie tylko jednej metody.
Wykonaj wywołanie uśpienia / oczekiwania / zatrzymania przez 1000 ms tuż przed wywołaniem metody?

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

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

Edytuj: Powyższa odpowiedź dotyczy pytania ogólnego „Jak mogę opóźnić wywołanie metody o 1 sekundę?”, Które było pytaniem zadawanym w momencie udzielenia odpowiedzi (w rzeczywistości odpowiedź została udzielona w ciągu 7 minut od pierwotnego pytania: - )). Nie podano wówczas żadnych informacji o języku, więc uprzejmie przestań narzekać na właściwy sposób korzystania ze snu i XCode oraz brak zajęć ...


Tylko w bieżącym wątku inne wątki będą nadal działać.
Marc Charbonneau

4
Jezu. Rozumiem, dlaczego głosowano na to kilka razy w dół, ale kto do cholery widział to przy -27 i zdecydował, że potrzebuje innego? Czy -3 lub coś innego nie przekazuje sedna sprawy. Dlaczego nie zmienić odpowiedzi, aby powiedzieć „to wstrzyma cały wątek” lub coś w tym stylu, zamiast głosować w dół, ludzie?
Albert Renshaw,

A co jeśli chcesz po prostu wstrzymać cały wątek? Wydaje się, że jest to ważna opcja, jeśli zawiera przyzwoite ostrzeżenie.
Departamento B

@AlbertRenshaw Całkowicie się z tobą zgadzam. Jestem tutaj i jest 35 upadków i oddałem mu swoją górę. Bardziej widzę tak kiepskie atakowanie użytkowników o niskiej reputacji. Nikt nie będzie niczego edytować ani określać. Widziałem dzisiaj jedną odpowiedź, że naprawdę utonęli. Jedynym błędem, jaki popełniła ta osoba, jest udzielenie szybkiej odpowiedzi z obiektywnym językiem c. Jeśli to ogromny błąd, chcę pokazać tak wiele szybkich odpowiedzi w ramach obiektywnych pytań.
soorej babu
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.