Czy ktoś może wyjaśnić, co to jest NSRunLoop
? więc jak wiem, NSRunLoop
jest to coś związanego, NSThread
prawda? Więc załóżmy, że tworzę wątek podobny do
NSThread* th=[[NSThread alloc] initWithTarget:self selector:@selector(someMethod) object:nil];
[th start];
-(void) someMethod
{
NSLog(@"operation");
}
więc po tym, jak ten wątek zakończy pracę, prawda? dlaczego używać RunLoops
lub gdzie używać? z dokumentów Apple Coś przeczytałem, ale nie jest to dla mnie jasne, więc proszę wyjaśnij tak prosto, jak to tylko możliwe
ios
objective-c
cocoa-touch
nsrunloop
taffarel
źródło
źródło
Odpowiedzi:
Pętla uruchamiania to abstrakcja, która (między innymi) zapewnia mechanizm do obsługi systemowych źródeł wejściowych (gniazd, portów, plików, klawiatury, myszy, zegarów itp.).
Każdy NSThread ma własną pętlę uruchamiania, do której można uzyskać dostęp za pomocą metody currentRunLoop.
Generalnie nie ma potrzeby bezpośredniego dostępu do pętli uruchamiania, chociaż istnieją pewne komponenty (sieciowe), które mogą pozwolić na określenie, której pętli będą używać do przetwarzania we / wy.
Pętla uruchamiania dla danego wątku będzie czekać, aż jedno lub więcej jego źródeł wejściowych będzie miało jakieś dane lub zdarzenia, a następnie uruchomi odpowiednią procedurę obsługi wejścia w celu przetworzenia każdego źródła wejściowego, które jest „gotowe”.
Po wykonaniu tej czynności powróci do swojej pętli, przetwarzając dane wejściowe z różnych źródeł i „śpiąc”, jeśli nie ma pracy.
To opis na dość wysokim poziomie (próba uniknięcia zbyt wielu szczegółów).
EDYTOWAĆ
Próba odniesienia się do komentarza. Rozbiłam to na kawałki.
W rzeczy samej. NSRunLoop nie jest bezpieczny dla wątków i powinien być dostępny tylko z kontekstu wątku, który uruchamia pętlę.
Jeśli chcesz monitorować port, po prostu dodaj ten port do pętli uruchamiania, a następnie pętla uruchamiania będzie obserwować ten port pod kątem aktywności.
Możesz również jawnie dodać licznik czasu za pomocą
Pętla uruchamiania będzie przetwarzać wszystkie gotowe zdarzenia w każdej iteracji (zgodnie ze swoim trybem). Będziesz musiał przejrzeć dokumentację, aby dowiedzieć się o trybach uruchamiania, ponieważ jest to nieco poza zakresem ogólnej odpowiedzi.
W większości aplikacji główna pętla uruchamiania będzie działać automatycznie. Jednak jesteś odpowiedzialny za uruchomienie pętli uruchamiania i reagowanie na zdarzenia przychodzące dla wątków, które obracasz.
Nie jestem pewien, co masz na myśli. Nie dodajesz zdarzeń do pętli uruchamiania. Dodajesz źródła wejściowe i źródła licznika czasu (z wątku, który jest właścicielem pętli uruchamiania). Następnie pętla biegania obserwuje je pod kątem aktywności. Możesz oczywiście podać dane wejściowe z innych wątków i procesów, ale dane wejściowe będą przetwarzane przez pętlę uruchamiania, która monitoruje te źródła w wątku, który uruchamia pętlę uruchamiania.
W rzeczy samej. W rzeczywistości pętla uruchamiania „pozostanie” w procedurze obsługi zdarzeń, dopóki ta procedura obsługi zdarzenia nie zwróci. Możesz to zobaczyć w dowolnej aplikacji po prostu. Zainstaluj program obsługi dla każdej akcji we / wy (np. Naciśnięcie przycisku), która jest w stanie uśpienia. Będziesz blokować główną pętlę uruchamiania (i cały interfejs użytkownika) do czasu zakończenia tej metody.
To samo dotyczy każdej pętli uruchamiania.
Proponuję przeczytać następującą dokumentację dotyczącą pętli uruchamiania:
https://developer.apple.com/documentation/foundation/nsrunloop
i jak są używane w wątkach:
https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/Multithreading/RunLoopManagement/RunLoopManagement.html#//apple_ref/doc/uid/10000057i-CH16-SW1
źródło
performSelector:onThread:withObject:waitUntilDone:
, przekazującNSThread
obiekt, a twój selektor zostanie zaplanowany w pętli uruchomieniowej tego wątku.Pozwalają one czekać, aż użytkownik naciśnie klawisz i odpowiednio zareagować, poczekać, aż pojawi się completeHandler i zastosować jego wyniki, poczekać, aż pojawi się licznik czasu i wykonać funkcję. Jeśli nie masz pętli, nie możesz słuchać / czekać na stuknięcia użytkownika, nie możesz czekać, aż rozpocznie się połączenie sieciowe, nie możesz zostać obudzony w ciągu x minut, chyba że użyjesz
DispatchSourceTimer
lubDispatchWorkItem
Również z tego komentarza :
W szczególności o: „Wątki w tle nie mają własnych pętli uruchomieniowych”. Następujący licznik czasu nie uruchamia się dla wysłania asynchronicznego :
Myślę, że powodem, dla którego
sync
blok również działa, jest to, że:syncbloki zwykle wykonywane z kolejki źródłowej . W tym przykładzie kolejka źródłowa jest kolejką główną, niezależnie od kolejki jest kolejką docelową.
Aby to sprawdzić, logowałem się
RunLoop.current
do każdej wysyłki.Wysłanie synchronizacji miało ten sam runloop co główna kolejka. Podczas gdy RunLoop w bloku async był inną instancją niż pozostałe. Możesz się zastanawiać, dlaczego tak się dzieje
RunLoop.current
zwraca inną wartość. Czy to nie wspólna wartość !? Świetne pytanie! Czytaj dalej:WAŻNA UWAGA:
Właściwość klasy
current
NIE jest zmienną globalną.Jest kontekstowe. Jest to widoczne tylko w zakresie wątku, czyli magazynu lokalnego wątku . Więcej na ten temat znajdziesz w tutaj .
Jest to znany problem z licznikami czasu. Nie masz tego samego problemu, jeśli używasz
DispatchSourceTimer
źródło
RunLoops to trochę jak pudełko, w którym coś się po prostu dzieje.
Zasadniczo w RunLoop przechodzisz do przetwarzania niektórych zdarzeń, a następnie wracasz. Lub wróć, jeśli nie przetwarza żadnych zdarzeń przed przekroczeniem limitu czasu. Możesz powiedzieć, że jest to podobne do asynchronicznych połączeń NSURLConnections, Przetwarzanie danych w tle bez zakłócania pętli prądowej, ale jednocześnie potrzebujesz danych synchronicznie. Można to zrobić za pomocą RunLoop, który sprawia, że Twoje jest asynchroniczne
NSURLConnection
i dostarcza dane w czasie wywołania. Możesz użyć RunLoop w następujący sposób:W tym RunLoop będzie działać, dopóki nie wykonasz innej pracy i nie ustawisz YourBoolFlag na false .
Podobnie możesz ich używać w wątkach.
Mam nadzieję, że to ci pomoże.
źródło
Stąd
Stąd
źródło