2009-12-17 10 views
32

Obecnie pracuję przy założeniu, że -performSelector:withObject:afterDelay: nie używa wątków, ale planuje zdarzenie do uruchomienia w późniejszym terminie w bieżącym wątku. Czy to jest poprawne?W jaki sposób -performSelector: withObject: afterDelay: work?

Bardziej konkretnie:

- (void) methodCalledByButtonClick { 
    for (id obj in array) { 
    [self doSomethingWithObj:obj]; 
    } 
} 

static BOOL isBad = NO; 
- (void) doSomethingWithObj:(id)obj { 
    if (isBad) { 
    return; 
    } 
    if ([obj isBad]) { 
    isBad = YES; 
    [self performSelector:@selector(resetIsBad) withObject:nil afterDelay:0.1]; 
    return; 
    } 
    //Do something with obj 
} 

- (void) resetIsBad { 
    isBad = NO; 
} 

To jest zagwarantowane, że -resetIsBad nie zostanie wywołana dopiero po -methodCalledByButtonClick zwrotów, zakładając, że są wyświetlane w głównym wątku, nawet jeśli -methodCalledByButtonClick bierze dowolnie długo, aby zakończyć?

Odpowiedz

44

Z docs:

Wywołuje metodę odbiornik bieżący wątek wykorzystuje domyślny tryb z opóźnieniem.

Dyskusja idzie dalej:

Ta metoda ustawia timer do wykonywania wiadomość aSelector na pętli wykonać bieżącego wątku. Licznik czasu to skonfigurowany do pracy w trybie domyślnym (NSDefaultRunLoopMode). Po uruchomieniu odliczacza czasowego wątek podejmie próbę usunięcia komunikatu z pętli uruchomienia i wykonania selektora. Udaje się, jeśli uruchamia pętlę iw trybie domyślnym ; w przeciwnym razie zegar czeka, aż pętla uruchamiania znajdzie się w domyślnym trybie .

Dzięki temu możemy odpowiedzieć na twoje drugie pytanie. Tak, jest to gwarantowane, nawet z krótszym opóźnieniem, ponieważ bieżący wątek jest zajęty wykonywaniem po wywołaniu performSelector. Gdy wątek wróci do pętli uruchamiania i usunie pismo z selektora, zwrócisz go ze swojej methodCalledByButtonClick.

12

performSelector:withObject:afterDelay: planuje timer w tym samym wątku, aby wywołać selektor po upływie opóźnienia. Jeśli zarejestrujesz się w domyślnym trybie uruchamiania (tzn. Nie użyjesz performSelector:withObject:afterDelay:inModes:), uważam, że gwarantuję, że zaczekasz do następnego przejścia przez pętlę uruchamiania, więc wszystko na stosie zostanie ukończone jako pierwsze.

Nawet jeśli zadzwonisz z opóźnieniem 0, będzie czekać do następnej pętli i zachowywać się, jak chcesz tutaj. Aby uzyskać więcej informacji, patrz the docs.

+1

Czy jest zagwarantowane, że opóźnienie o wartości 0 nadal nie spowoduje natychmiastowego uruchomienia? Doktorzy mówią "niekoniecznie", ale to coś innego niż "koniecznie nie", więc jestem ciekawy. –

+0

To zawsze działało w ten sposób z mojego doświadczenia, ale dobry punkt. Nie wiem, czy jest to gwarantowane. –

+0

Miałem ten sam problem i to działało dla mnie [self performSelector: @selector (showLoginScreen) withObject: nil afterDelay: 1.0]; –

Powiązane problemy