2008-10-03 17 views
5

Gdybym tarło nowy wątek, a następnie w nim wciskam nowy kontroler na moim UINavigationController, przy użyciu kodu takiego ...NSThread i UIViewController interakcja

(a) nie działa

-(void)myCallbackInThread 
{ 
    // move on... 
    UIApplication* app = [UIApplication sharedApplication]; 
    [app changeView]; 
} 

następnie stwierdzam, że widok pojawia się, ale nie odpowiada na dane wprowadzone przez użytkownika.

Gdybym zmienić kod podobny do tego

(b) obróbkę

-(void)myCallbackInThread 
{ 
    // move on... 
    UIApplication* app = [UIApplication sharedApplication]; 
    [app performSelectorOnMainThread:@selector(moveToMain) withObject:nil waitUntilDone:FALSE]; 
} 

Wtedy wszystko działa dobrze.

Jakieś wskazówki, dlaczego?

+0

Czy otrzymujesz coś w oknie konsoli? Znalazłem z wątków na iPhone, jeśli robisz coś zabawnego, że wyprowadza wiadomości dziennika. – Lounges

Odpowiedz

2

W twoim przypadku to naprawdę zależy od tego, co dzieje się w [app changeView], ale powodem, dla którego przestaje odpowiadać, jest najprawdopodobniej brak zdarzeń uruchomienia pętli w nowym, dodatkowym wątku (więcej na ten temat poniżej). Ogólnie jednak bardzo zły jest aktualizowanie GUI z dodatkowego wątku. Jak już odkryłeś, wszystkie te wydarzenia powinny przejść przez główny wątek.

Głównym powodem tego, że twój drugi przykład działa, a nie twój pierwszy, jest to, że UIApplication ustawia i obsługuje pętlę uruchamiania i narzędzie do rozsyłania zdarzeń w głównym wątku. Tak więc, gdy wywołasz metodę performSelectorInMainThread, selektor zostanie wywołany do głównej pętli, która będzie w stanie obsłużyć twoje wejście GUI i inne zdarzenia. Program rozsyłający zdarzenia jest również uruchamiany i zarządzany przez UIApplication w głównym wątku.

Zasadniczo nie należy wykonywać żadnych czynności zarządzania grafikami w wątku dodatkowym. Wyślij je do głównego wątku. A jeśli potrzebujesz przetwarzania na wątku dodatkowym (dla takich rzeczy jak liczniki czasu lub połączenia asynchroniczne itp.) następnie musisz uruchomić i zarządzać własną pętlą uruchamiania w tym wątku (więcej informacji na temat zarządzania pętlą uruchomieniową znajdziesz w artykule NSRunLoop).

2

Wystarczy znaleźć to w docs iPhone gwintowania

Jeśli aplikacja ma graficzny interfejs użytkownika, zaleca się pojawić wydarzenia związane użytkownika i inicjować aktualizacje interfejsu od głównego wątku danej aplikacji . To podejście pozwala uniknąć problemów związanych z obsługą zdarzeń użytkownika i zawartości okna rysunku. Niektóre frameworki, takie jak kakao, generalnie wymagają tego zachowania, ale ma także tę zaletę, że pozwala na uproszczenie logiki zarządzania Twoim interfejsem użytkownika.

Nadal nie widzę, co tak naprawdę powoduje, że coś jest wyświetlane, ale nie można odbierać danych wprowadzanych przez użytkownika, ale postąpię zgodnie z wytycznymi w przyszłości.

2

Dokumentacja mówi: "Jeśli nie masz pewności co do konkretnej operacji graficznej, zaplanuj wykonanie tego z głównego wątku".

Dobrą zasadą do naśladowania jest to, że jeśli klasa nie jest jawnie udokumentowana jako bezpieczna dla wątków, to prawdopodobnie nie. Ponadto kod, który nie został udokumentowany jako bezpieczny dla wątków, nie może szybko zawieść, gdy jest używany przez wiele wątków, ale może po prostu wykazywać niezdefiniowane zachowanie, jak widzieliśmy.

0

Prawie żaden kod UI w UIKit lub AppKit nie jest bezpieczny dla wątków. Sposób, w jaki się nie powiedzie, jest nieistotny, ponieważ jeśli martwisz się, jak to się nie uda, robisz coś, co spowoduje różnego rodzaju dziwne błędy, które subtelnie zmienią się pomiędzy różnymi wersjami systemu operacyjnego.

Moja najlepsza rada to nie używać rzeczy z wątków w tle, chyba że dokumentacja mówi, że jest bezpieczna.