Mam UIWebView w viewcontroller, który ma dwie metody, jak poniżej. Pytanie brzmi: jeśli wyskoczę (stukam w pasek nawigacyjny) tego kontrolera przed wykonaniem drugiego wątku, aplikacja ulegnie awarii po [super zwolnieniu], ponieważ "Próbowano uzyskać blokadę sieci z wątku innego niż główny wątek lub wątku internetowego. Może to być wynikiem wywołania UIKit z wątku dodatkowego. ". Każda pomoc będzie naprawdę doceniona.UIWebView w wielowątkowej ViewController
Odpowiedz
Miałem takie samo rozwiązanie, w którym wątek tła był ostatnim wydaniem, powodując dealloc kontrolera widoku, aby wystąpił w wątku tła kończącym się z tą samą awarią.
Powyższa [[self retain] autorelease]
nadal będzie powodować, że ostateczne wydanie dzieje się z puli autorelease wątku tła. (Chyba że jest coś specjalnego w wydaniach z puli autorelease, jestem zaskoczony, że to by miało znaczenie).
Znalazłem to jako mój idealne rozwiązanie, umieszczając ten kod do mojego widoku klasie kontrolera:
- (oneway void)release
{
if (![NSThread isMainThread]) {
[self performSelectorOnMainThread:@selector(release) withObject:nil waitUntilDone:NO];
} else {
[super release];
}
}
Gwarantuje to, że metoda mojej klasie widok kontrolera release
jest zawsze wykonywany na głównym wątku.
Jestem trochę zaskoczony, że niektóre przedmioty, które mogą być prawidłowo dealloc'ed tylko z głównego wątku nie masz jeszcze coś takiego wbudowane w. No cóż ...
To zakończyło dla mnie poważny ból głowy. Dzięki! – spstanley
Cieszę się, że znalazłem to - kwiecień 2011 – GuybrushThreepwood
Dzięki za tonę !! –
Zasadniczo należy anulować wszelkie operacje w tle, gdy widok, który ich używa, znika. Jak w:
- (void)viewWillDisappear:(BOOL)animated {
[operationQueue cancelAllOperations];
[super viewWillDisappear:animated;
}
Dziękuję za odpowiedź. Ale dodałem to i wydaje się, że dealloc jest zawsze wywoływany w wątku dodatkowym. Nadal nie potrafię zrozumieć przyczyny. – Tao
Anulowanie operacji w tle to "właściwy" sposób na zrobienie tego. Powód, dla którego nie rozwiązuje problemu, polega na tym, że 'cancelAllOperations' nie przerywa automatycznie już działających operacji. To, co musisz zrobić, to w metodzie 'load', po snu wątku, sprawdź właściwość' isCancelled' operacji; jeśli tak, zwróć bez wywoływania 'done'. Ale jeśli wszystko, co robisz, jest po prostu pauzowaniem w wątku tła, łatwiejszy sposób to zrobić z 'performSelector: withObject: afterDelay:'. –
nie jestem pewien dokładnie, co się dzieje na podstawie kodu, ale wygląda na to viewDidAppear jest uzyskiwanie nazywa i tworząc drugą nitkę, a następnie jesteś przechodząc od kontrolera i zwalniając go , a następnie drugi wątek kończy i wywołuje performSelectorOnMainThread na zwolnionym obiekcie "self". Myślę, że możesz po prostu sprawdzić, czy wydanie nie nastąpiło?
Komunikat o błędzie, który otrzymujesz, oznacza, że uruchamiasz jakiś kod UIKit z drugiego wątku. Apple ostatnio dodał kilka sprawdzeń dla wątkowych wywołań do UIKit, i myślę, że prawdopodobnie potrzebujesz tylko refaktoryzować swoją funkcję ładowania, aby zaktualizować interfejs na głównym wątku, zamiast wywoływać funkcje UIWebView z drugiego wątku.
Nadzieję, że pomaga!
Obecnie mam podobny problem w mojej aplikacji. Kontroler widoku wyświetlający interfejs UIWebView jest przesyłany do kontrolera nawigacyjnego i uruchamia wątek tła, aby pobrać dane. Jeśli naciśniesz przycisk Wstecz przed zakończeniem wątku, aplikacja ulegnie awarii z tym samym komunikatem o błędzie.
Problem polega na tym, że NSThread
zachowuje cel (własny) i obiekt (argument) i zwalnia go po uruchomieniu metody - niestety uwalnia obie z wewnątrz wątku. Tak więc po utworzeniu kontrolera liczba zatrzymań wynosi 1, gdy wątek jest uruchamiany, kontroler otrzymuje wartość zatrzymania równą 2. Po naciśnięciu kontrolera przed zakończeniem wątku kontroler nawigacyjny zwalnia kontroler, co powoduje zachowaj liczbę 1. Jak na razie jest to w porządku - Ale jeśli wątek w końcu się zakończy, NSThread
zwalnia kontroler, co skutkuje licznikiem zatrzymania równym 0 i natychmiastowym zwolnieniem z wątku. To sprawia, że UIWebView (który jest wydany w dealloc metody kontrolera) podnieść wyjątek i awarię ostrzeżenia o wątku.
Udało mi się obejść ten problem, używając [[self retain] autorelease]
jako ostatniej instrukcji w wątku (tuż przed uwolnieniem wątku przez pulę). Gwarantuje to, że obiekt kontrolera nie zostanie natychmiast zwolniony, ale zostanie oznaczony jako autoodpowiedziany i zwolniony później w pętli uruchamiania głównego wątku. Jest to jednak nieco brudny hack i wolałbym raczej znaleźć lepsze rozwiązanie.
Twoje rozwiązanie "obejść" działa dla mnie, dzięki. BTW, Tao, jaka jest twoja ostatnia decyzja, której metody używasz? – RoundOutTooSoon
w rzeczywistości jesteś przecieka pamięć ... !! – Ricibald
Próbowałem obu rozwiązań przedstawionych powyżej, [operationQueue cancelAllOperations]
i [[self retain] autorelease]
. Jednak za pomocą szybkiego kliknięcia nadal istnieją przypadki, w których liczba zatrzymań spada do 0, a klasa zostaje zwolniona na wątku dodatkowym. W celu uniknięcia katastrofy, kładę następujących w moim dealloc
teraz:
if ([NSThread isMainThread]) {
[super dealloc];
}
co jest oczywistym wyciek, ale wydaje się być mniejsza od 2 zła.
Wszelkie dodatkowe informacje od osób, które mają ten problem, są mile widziane.
Próbowałem:
[self retain];
[self performSelectorOnMainThread:@selector(release) withObject:nil waitUntilDone:NO];
który wydaje się działać jeszcze lepiej.
Oto kod uruchamiać elementy UIKit w głównym wątku. Jeśli pracujesz nad innym wątkiem i musisz uruchomić fragment kodu UIKit, po prostu umieść go między nawiasami tego fragmentu Grand Central Dispatch.
dispatch_async(dispatch_get_main_queue(), ^{
// do work here
});
- (void)dealloc
{
if(![NSThread isMainThread]) {
[self performSelectorOnMainThread:@selector(dealloc)
withObject:nil
waitUntilDone:[NSThread isMainThread]];
return;
}
[super dealloc];
}
podczas pisania kodu najlepiej jest dodać krótkie wyjaśnienie – ronalchn
- 1. Ostatni wątek aplikacji wielowątkowej
- 2. Profilowanie/optymalizacja aplikacji wielowątkowej
- 3. Prezentacja storyboardu ViewController z innego ViewController
- 4. Swift: TableView w ViewController
- 5. Błąd konfiguracji Fluktuacji Nhibernate w aplikacji wielowątkowej
- 6. Jak korzystać z Hibernate w aplikacji wielowątkowej?
- 7. DLL i klasa w aplikacji wielowątkowej
- 8. Ogólne podejście do NSManagedObjectContext w wielowątkowej aplikacji
- 9. Błąd segmentacji w bibliotece libcurl, wielowątkowej
- 10. Osadzanie pythona w aplikacji wielowątkowej C
- 11. Opóźnienie UIWebView podczas wczytywania treści lokalnych
- 12. Swift: niestandardowe inicjalizatory ViewController
- 13. pokaż UIAlertController poza ViewController
- 14. NSLayoutConstraint wywala ViewController
- 15. Ładowanie ciąg w UIWebView
- 16. EXC_BAD_ACCESS w UIWebView
- 17. Przycisk Wstecz w UIWebView
- 18. NSString w UIWebview
- 19. uWSGI i wdzięcznie zabijanie wielowątkowej aplikacji Flask
- 20. Jak usunąć poziomy z wielowątkowej ramki danych?
- 21. UIWebView stringByEvaluatingJavaScriptFromString
- 22. Jak ustawić nagłówek "User-Agent" w UIWebView w Swift
- 23. UIWebView spodnia
- 24. Prawidłowe użycie yieldIfContendedSafely() w aplikacji wielowątkowej z systemem Android
- 25. Wykonywanie kwerendy wielowątkowej Elastic Scale w kontekście bazy danych
- 26. Czy istnieje sposób bezpiecznego korzystania z errno w aplikacji wielowątkowej?
- 27. Popping do konkretnego viewcontroller w stos nawigacyjnym
- 28. Jak zaimportować plik AppDelegate.h w podglądzie ViewController?
- 29. Programowo wróć do poprzedniego ViewController w Swift
- 30. iOS: jak przekazać ViewController w bieżącym kontekście?
[My Roztwór (wykorzystuje NSTimer w ostatnim wydaniu)] (http://stackoverflow.com/questions/6353471/block-release-deallocating-ui-objects-on-a-background -thread/6482941 # 6482941 "Moje rozwiązanie") – Jeff