OK, oto umowa, nienawidzę zadawać pytań dotyczących mojego debugowania i awarii. Ponieważ zwykle sam sobie z nimi radzę, ale po prostu nie mogę sobie z tym poradzić , nawet po przejrzeniu wielu pytań .
OK, więc tutaj jest problem, moja aplikacja losowo włącza się i wyłącza z tym śladem stosu:
*** -[ViewController respondsToSelector:]: message sent to deallocated instance 0x1e5d2ef0
Gdzie ViewController
może się różnić, czasami miejsce, w którym mój kod ulega awarii, NIEViewController
ma żadnego związku z tym konkretnym i nie jest jego właścicielem ani nie nazywa go.
Ponadto, aby uzyskać śledzenie konsoli, włączyłem Zombies, w przeciwnym razie nie uzyskałbym żadnego wydruku konsoli, dostałbym tylko:, objc_msgSend
co wiem, oznacza, że wysyłam wiadomość do czegoś, co zostało wydane. Ale nie mogę znaleźć tego, gdzie to jest ... Naprawdę utknąłem! Zwykle zawsze debuguję swoje awarie, więc naprawdę utknąłem na tym.
Ponownie, powoduje to awarie w różnych miejscach w różnym czasie, z włączaniem i wyłączaniem. Miejsce awarii nie ma prawie żadnego związku z ViewController
. Uważam to za bardzo zagmatwane.
Potrzebujesz mojego kodu? Mam dużo plików, a ponieważ program się zawiesza w różnych miejscach, dystrybucja mojego kodu będzie bałaganem!
Próbowałem dodać symboliczne punkty przerwania bez powodzenia, a Zombies nie jest dostępny w aplikacji Instruments na iOS. Nie mogę uruchomić mojej aplikacji na symulatorze, ponieważ ma ona nieobsługiwane struktury architektury.
Dziękuję wszystkim...
źródło
Odpowiedzi:
Użyj Instrumentów, aby wyśledzić cofnięte błędy instancji. Profiluj swoją aplikację ( Cmd ⌘+ I) i wybierz szablon Zombies . Po uruchomieniu aplikacji spróbuj ją zawiesić. Powinieneś dostać coś takiego:
Kliknij strzałkę obok adresu w wyskakującym okienku, aby wyświetlić obiekt, który został wywołany po cofnięciu przydziału.
Powinieneś teraz zobaczyć każde wywołanie, które się zmieniło, zachowuje licznik tego obiektu. Może to być spowodowane bezpośrednim wysyłaniem wiadomości o zachowaniu / zwolnieniu, a także opróżnianiem puli autowyrejestrowań lub wstawieniem do NSArrays.
Kolumna RefCt pokazuje retainCount po wywołaniu akcji, a Responsible Caller pokazuje nazwę klasy i metodę, w której została wykonana. Po dwukrotnym kliknięciu dowolnego zatrzymania / zwolnienia instrumenty pokażą wiersz kodu, w którym zostało to wykonane (jeśli to nie działa, możesz sprawdzić połączenie, zaznaczając je i wybierając jego odpowiednik w okienku Rozszerzone szczegóły ):
Umożliwi to zbadanie całego cyklu życia obiektu retainCount i prawdopodobnie od razu znajdziesz swój problem. Wszystko co musisz zrobić, to znaleźć brakuje zachować dla najnowszego wydania .
źródło
release
. Problemem jest to, każdy niezrównoważonyrelease
. Mogę też być po prostu niepowodzeniem wretain
czymś, do czego masz wskaźnik i odnosisz się później.miał podobny problem. W moim przypadku viewController musiał pobrać zdarzenia navigationController, więc rejestrował się jako delegat kontrolera nawigacji:
Awaria występuje, gdy ten kontroler został zwolniony, ale nadal był delegatem dla kontrolera widoku. Dodanie tego kodu w dealloc nie przyniosło żadnego efektu:
ponieważ w momencie wywołania dealloc kontroler widoku został już usunięty z hierarchii widoków, więc self.navigationController ma wartość zero, więc porównanie jest gwarantowane niepowodzeniem! :-(
Rozwiązaniem było dodanie tego kodu w celu wykrycia VC opuszczającego hierarchię widoku tuż przed tym, jak faktycznie to zrobi. Używa metody wprowadzonej w iOS 5 do określenia, kiedy widok jest wyskakujący, a nie wypychany
Nigdy więcej awarii!
źródło
Dla każdego, kto nie może tego rozwiązać, oto kilka innych technik:
https://stackoverflow.com/a/12264647/539149
https://stackoverflow.com/a/5698635/539149
https://stackoverflow.com/a/9359792/539149
https://stackoverflow.com/a/15270549/539149
https://stackoverflow.com/a/12098735/539149
Możesz uruchomić Instruments w Xcode 5, klikając wyskakujące okienko projektu-> Edytuj schemat ... Profil -> Instrument i wybierz Alokacje lub Wycieki, a następnie profiluj swoją aplikację, następnie zatrzymaj instrumenty, kliknij przycisk informacji w Alokacjach i „Włącz wykrywanie NSZombie” .
Jednak w przypadku wiadomości pochodzących bezpośrednio z wątku com.apple.main-thread prawdopodobnie niczego to nie ujawni.
Waliłem w to głowę przez ponad dwie godziny, a odpowiedź okazała się nadwyżką, którą odkryłem, komentując kopię mojego projektu brutalną siłą, dopóki nie znalazłem winowajcy:
Problem polega na tym, że release nie ustawia zmiennej na NULL.
Oznacza to, że ustawienie go na NULL wywołuje zwalnianie ponownie, zmniejszając refcount i natychmiast zwalniając pamięć, aż do późniejszego zakończenia zmiennych, które odwołują się do viewController.
Więc włącz ARC lub upewnij się, że projekt konsekwentnie używa wydania lub NULL, ale nie obu. Wolę używać NULL, ponieważ wtedy nie ma szans na odniesienie się do zombie, ale utrudnia to znalezienie miejsca, w którym obiekty są uwalniane.
źródło
Wczoraj spotkałem się z tym samym problemem w iOS. Utworzyłem IAP w podglądzie „Informacje” aplikacji i dodałem Obserwator transakcji w widoku „Informacje” viewDidLoad. Kiedy kupuję po raz pierwszy, nie ma problemu, ale po powrocie do głównego okna i ponownym wejściu o podglądzie do zakupu, pojawił się problem „wiadomość wysłana do cofniętej instancji” i aplikacja uległa awarii.
Po usunięciu obserwatora transakcji w dealloc problem został rozwiązany.
źródło
zombie
Otrzymałem obiekt do zakupów w aplikacji. Po wielu godzinach kopania znalazłem ten… WIELKIE DZIĘKI Człowieku.Miałem bardzo podobny problem i doszedłem do wniosku, że jest to spowodowane ustawieniem delegatów kontrolera nawigacji.
Poniższe rozwiązało mój problem,
źródło
Miałem ten sam problem w OS X.
Aby rozwiązać tę niewystarczającą
- (void)dealloc
metodę, jak już powiedział @SoftwareEvolved. Ale niestety- (void)viewWillDisappear
jest dostępny tylko w wersji 10.10 i nowszych.Wprowadziłem niestandardową metodę w mojej podklasie NSViewController, w której ustawiłem wszystkie odniesienia niebezpieczne dla zombie na nil. W moim przypadku były to
NSTableView
właściwości (delegate
idataSource
).To wszystko. Za każdym razem, gdy mam zamiar usunąć widok z okna nadzoru, wywołaj tę metodę.
źródło
Miałem ten sam problem. Trudno było znaleźć delegata, który powoduje problem, ponieważ nie wskazuje on żadnej instrukcji w wierszu ani kodzie, więc spróbuję jakiś sposób, może to okaże się pomocne.
źródło