2012-10-12 13 views
5

Mam potrzebę opóźnienia o określoną ilość czasu, a jednocześnie zezwalam na dalsze działanie innych rzeczy na tym samym runloopie. Używam następujący kod, aby to zrobić:Właściwy sposób na opóźnienie, pozwalając na kontynuowanie pętli uruchamiania

[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:1]]; 

Wydaje się to zrobić dokładnie to, co chcę, oprócz tego, że czasami zwraca natychmiast, bez czekania żądany czas (1 sekunda).

Czy ktoś może mi powiedzieć, co może spowodować? I jaki jest właściwy sposób oczekiwania na uruchomienie pętli uruchamiania?

UWAGA: Chcę opóźnić w sposób podobny do trybu uśpienia(), tak aby po opóźnieniu powróciłem do tego samego strumienia wykonywania, co poprzednio.

+0

Czego chcesz się opóźnić? Czy spojrzałeś na 'dispatch_after'? –

+0

Chcę opóźnić bieżący wątek w sposób podobny do trybu uśpienia(), z wyjątkiem tego, że chcę, aby runloop nadal działał (aby inne zdarzenia i inne rzeczy mogły się uruchomić) podczas tego czasu opóźnienia. – Locksleyu

Odpowiedz

8

Powinieneś użyć do tego GCD i dispatch_after. Jest znacznie nowszy i bardziej wydajny (i bezpieczny w wątkach i wszystko) i bardzo łatwy w użyciu.

Jest nawet fragment kodu osadzony w Xcode tak, że jeśli zaczniesz wpisywać dispatch_after będzie sugerować fragment i jeśli potwierdzić to napisze przygotowanej 2-3 wierszy dla Ciebie w kodzie :)

Code Snippet suggestion by Xcode

int64_t delayInSeconds = 2.0; 
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC); 
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ 
    <#code to be executed on the main queue after delay#> 
}); 
+1

Wymieniona metoda uruchamia inny fragment kodu w głównej kolejce, co zasadniczo polega na opóźnieniu o pewien okres czasu i powrocie do kodu, który miałem wcześniej. Na przykład, jeśli miałem pętlę for, która wykonała wydruk, poczekaj sekundę, a następnie powtórz. Chcę, żeby oświadczenie po prostu "uśpiło" na sekundę, a następnie wróciło do pętli for, którą miałem wcześniej. Czy to ma sens? – Locksleyu

+1

To ma i nie ma sensu. Możesz to zrobić, ustawiając wątek w stan uśpienia ('[NSThread sleepForTimeinterval:]' lub 'usleep()'?), Ale spowoduje to aktywną pauzę, która nie jest zalecana we właściwych schematach programowania OOP. A jeśli uruchomisz pętlę for na głównym runloopie, oczywiście "zamrozi" twoją aplikację. To prawdopodobnie zły projekt. – AliSoftware

+2

Rozwiązaniem, które widzę, jeśli naprawdę chcesz wykonać N iteracji, każda oddzielona przez 1 sekundę, jest "for (int i = 0; i AliSoftware

1

Użyj NSTimer do wywołania połączenia z pewną metodą po pewnym opóźnieniu.

1

The accepted SO answer here powinien pomóc. Możesz także zaimplementować adres wysyłki (explained here) Davida, co jest bardziej aktualnym sposobem na zrobienie tego samego, używając GCD.

Jest kilka takich funkcji GCD, które warto poznać i są bardzo łatwe w użyciu.

+0

Dzięki za odpowiedź. Nie jest to jednak dokładnie to, czego szukam (przepraszam, jeśli nie byłem pewien w poście). Chcę zasadniczo zablokować bieżący wątek (podobny do snu (1)), a następnie przywrócić kontrolę w miejscu, w którym byłam wcześniej. Kod, który połączyłeś, wykonuje "jakiś inny kod" po pewnym czasie, zamiast tylko zwracać kontrolę do mojego wątku, aby móc kontynuować od miejsca, w którym przerwałam. Podany przeze mnie przykład to robi, ale czasami nie udaje się prawidłowo opóźnić. – Locksleyu

0

Czy próbowałeś performSelector:withObject:afterDelay:?

Z Apple documentation

Wywołuje metodę odbiornika na bieżącym wątku wykorzystuje domyślny tryb z opóźnieniem.

0

Miałem podobny problem i to jest moje rozwiązanie. Mam nadzieję, że działa również dla innych.

__block bool dispatched = false; 
while (put your loop condition here) 
{ 
    if (dispatched) 
    { 
     // We want to relinquish control if we are already dispatched on this iteration. 
     [ [ NSRunLoop currentRunLoop ] runMode: NSDefaultRunLoopMode beforeDate:[ NSDate date ] ]; 
     continue; 
    } 

    // mark that a dispatch is being scheduled 
    dispatched = true; 

    int64_t delayInNanoSeconds = (int64_t) (0.1 * (float) NSEC_PER_SEC); 
    dispatch_time_t delayTime = dispatch_time(DISPATCH_TIME_NOW, delayInNanoSeconds); 

    dispatch_after(delayTime, dispatch_get_main_queue(), ^() { 
     // Do your loop stuff here 
     // and now ready for the next dispatch 
     dispatched = false; 
    }); 
} // end of while 
Powiązane problemy