Xcode nie pokazuje linii, która powoduje awarię

126

Za każdym razem, gdy moja aplikacja ulega awarii, Xcode podświetla wywołanie UIApicationMain () w funkcji main () jako wiersz, który spowodował awarię. W niektórych przypadkach było to normalne (na przykład błąd segmentacji), ale awaria, z którą próbuję sobie poradzić, to prosty SIGABRT ze szczegółowymi informacjami zarejestrowanymi w konsoli:

*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFDictionary setObject:forKey:]: attempt to insert nil value (key: Date)'

Xcode pokazywał linię poprawnie ze starszymi SDK, ale od czasu aktualizacji do Xocde 4.2 to się zmieniło. Jest całkiem oczywiste, że Xcode dokładnie wie, co spowodowało awarię (lub może wiedzieć), ale nadal nie pokazuje rzeczywistej linii. Czy jest jakieś rozwiązanie lub obejście tego problemu?

JonasG
źródło
2
Czy kompilujesz do wydania? Jeśli tak, spróbuj ustawić schemat na Debugowanie.
epatel
Może się również zdarzyć, że jakiś xib jest zły, powodując awarię programu w miejscu z własnego kodu źródłowego, a tym samym nie wyświetlając żadnego pliku. Błąd opisuje problem dotyczący klucza słownika o nazwie „Data”
epatel
1
Apple powinno zatrudnić więcej testerów;)
Amr Lotfy

Odpowiedzi:

301

Powinieneś również upewnić się, że masz ustawione punkty przerwania dla wszystkich wyjątków. Spowoduje to zatrzymanie Xcode w wierszu, w którym występuje wyjątek. Wykonaj następujące czynności [w Xcode 4]:

  1. W Nawigatorze projektu po lewej stronie Xcode kliknij nawigator punktów przerwania (prawie do prawej strony górnego paska przycisków. Ikona wygląda jak gruba strzałka w prawo).

  2. W dolnej części nawigatora kliknij przycisk „+”.

  3. Kliknij „Dodaj punkt przerwania wyjątku”.

  4. Zostanie utworzony nowy punkt przerwania. Powinien być skonfigurowany zgodnie z potrzebami, ale możesz dostosować jego zachowanie.

  5. Uruchom projekt i odtwórz wyjątek.

Wspomniałeś również, że połączyłeś się z niektórymi bibliotekami / frameworkami stron trzecich. Jeśli wyjątek występuje w tych strukturach, będziesz miał trudności, ponieważ kod jest kompilowany, a Xcode nie może w rzeczywistości pokazać ci wiersza, który spowodował wyjątek. Jeśli tak jest i jesteś pewien, że używasz bibliotek poprawnie, powinieneś zgłosić błąd do opiekunów tych bibliotek.

Furman
źródło
4
Jestem noobem i rozwijałem się bez tego prawie miesiąc ... to zmienia moje życie.
Jonny Burger
4
Mój przyjaciel zarejestrował się na konto SO tylko po to, aby zagłosować za tym postem.
Alex Spencer,
1
w mojej książce nazywa się to połowiczną dupą jabłek
ChuckKelly,
1
Zrobiłem to, ale nadal nie mogę znaleźć miejsca, w którym
wywołało
1
To działa, ale wadą jest to, że nie wyświetla już szczegółów wyjątku w konsoli debugowania. Mogę więc WYŁĄCZYĆ ten punkt przerwania i zobaczyć szczegóły i ślad wyjątku, ale nie GDZIE to się stało, lub włączyć go, aby zobaczyć, gdzie to się stało, ale bez DLACZEGO. Czy ktoś wie, jak mieć oba?
Gabriel Jensen
27

Po prostu postępuj zgodnie z instrukcjami w tej odpowiedzi StackOverflow:

Włącz zombie

Zasadniczo wystarczy „włączyć zombie”. Następnie Xcode powinien się zepsuć w dowolnej linii powodującej problem.

wprowadź opis obrazu tutaj

(To absolutnie szokujące, że nawet w 2017 roku Xcode nadal ma to domyślnie wyłączone. Dlaczego nie chcesz widzieć linii, która spowodowała problem? I „ Włącz obiekty zombie ”?! Naprawdę?! Czy autorzy Xcode naprawdę wierzysz, że jest to użyteczna nazwa, która miałaby sens dla nowych programistów? To przygnębiające, jak słaba jest ocena Xcode rok po roku w App Store. Nikt nie słucha ...)

Mike Gledhill
źródło
6
Xcode to najgorsze środowisko programistyczne, jakiego do tej pory używałem.
Student
To, co mnie interesuje (jako programista Visual Studio), to ilu programistów Xcode, których spotkałem, którzy twierdzą, że Xcode jest najlepszym środowiskiem, jakiego kiedykolwiek używali. Logiczne, przyjazne i pomocne… ale z kilkoma dziwactwami. Nawet teraz, w listopadzie 2019 r., Xcode ma ocenę App Store na poziomie 3,1, a większość ludzi przyznaje mu 5 gwiazdek lub 1 gwiazdkę. Nikt nie słucha ...
Mike Gledhill
10

Edycja obecnego systemu i pozwalają NSZombieEnabled, MallocStackLoggingoraz guard malloc. Następnie, gdy aplikacja ulegnie awarii, wpisz w konsoli gdb:

(gdb) info malloc-history 0x543216

Zastąp 0x543216adres obiektu, który spowodował błąd NSInvalidArgumentExceptioni powinien on dać znacznie bardziej użyteczny ślad stosu, pokazujący wiersze kodu, które powodują awarię.

chown
źródło
1
Próbowałem tego i został wyrzucony błąd: „info” nie jest prawidłowym poleceniem. Jakakolwiek rada?
achi
@EliGregory upewnij się, że twój debugger jest ustawiony na gdb, a nie domyślny lldb. Możesz to zmienić w menu Edit Scheme w sekcji run.
chown
2

Widziałem to zachowanie w mocno zoptymalizowanym kodzie; Pomocne może być sprawdzanie, dostosowywanie poziomu optymalizacji celu i bibliotek innych firm. (Ustawienie poziomu optymalizacji LLVM 3.0)

Czy generujesz symbole debugowania?

FluffulousChimp
źródło
Zgoda. Jeśli próbujesz debugować, poziom optymalizacji musi być ustawiony na 0 (brak optymalizacji) w ustawieniach kompilacji.
Carter
1

Napisałem kod, aby wygenerować awarię indeksu poza wiązaniem. Poniżej znajduje się zgłoszony wyjątek.

2017-01-07 04:02:57.606 testABC[1694:52966] *** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSSingleObjectArrayI objectAtIndex:]: index 1 beyond bounds [0 .. 0]'
*** First throw call stack:
(
    0   CoreFoundation                      0x000000010e85cd4b __exceptionPreprocess + 171
    1   libobjc.A.dylib                     0x000000010e2be21e objc_exception_throw + 48
    2   CoreFoundation                      0x000000010e8b5c2f -[__NSSingleObjectArrayI objectAtIndex:] + 111
    3   testABC                             0x000000010dce962d -[ViewController ComplexFunction] + 61
    4   testABC                             0x000000010dce95db -[ViewController thirdFunction] + 43
    5   testABC                             0x000000010dce959b -[ViewController secondFunction] + 43
    6   testABC                             0x000000010dce955b -[ViewController firstFinction] + 43
    7   testABC                             0x000000010dce96c2 -[ViewController viewDidAppear:] + 50
    8   UIKit                               0x000000010ee28a6c -[UIViewController _setViewAppearState:isAnimating:] + 945
    9   UIKit                               0x000000010ee2b7da __64-[UIViewController viewDidMoveToWindow:shouldAppearOrDisappear:]_block_invoke + 42
    10  UIKit                               0x000000010ee29ac4 -[UIViewController _executeAfterAppearanceBlock] + 86
    11  UIKit                               0x000000010ec8d77c _runAfterCACommitDeferredBlocks + 653
    12  UIKit                               0x000000010ec7a273 _cleanUpAfterCAFlushAndRunDeferredBlocks + 566
    13  UIKit                               0x000000010ec9d757 __84-[UIApplication _handleApplicationActivationWithScene:transitionContext:completion:]_block_invoke_2 + 194
    14  CoreFoundation                      0x000000010e8016ac __CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__ + 12
    15  CoreFoundation                      0x000000010e7e66f4 __CFRunLoopDoBlocks + 356
    16  CoreFoundation                      0x000000010e7e5e65 __CFRunLoopRun + 901
    17  CoreFoundation                      0x000000010e7e5884 CFRunLoopRunSpecific + 420
    18  GraphicsServices                    0x00000001126d9a6f GSEventRunModal + 161
    19  UIKit                               0x000000010ec80c68 UIApplicationMain + 159
    20  testABC                             0x000000010dce99df main + 111
    21  libdyld.dylib                       0x000000011174968d start + 1
    22  ???                                 0x0000000000000001 0x0 + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException

Jeśli uważnie przeczytasz First Throw call stack

0   CoreFoundation              0x000000010e85cd4b __exceptionPreprocess + 171
1   libobjc.A.dylib             0x000000010e2be21e objc_exception_throw + 48

0 and 1 to procesy systemowe po awarii.

 2   CoreFoundation             0x000000010e8b5c2f -[__NSSingleObjectArrayI objectAtIndex:] + 111

2 to linia, która spowodowała wyjątek.

3   testABC                     0x000000010dce962d -[ViewController ComplexFunction] + 61

3informuje, że nazwa klasy ( ViewController) i funkcja naem ( ComplexFunction), w której został zgłoszony wyjątek.

AsifHabib
źródło
4
Errr, dobrze. Masz całkowitą rację, ale czy to jest przyjazne? W każdym nowoczesnym środowisku programistycznym (od lat 90. XX wieku), gdy wystąpi wyjątek, zostaniesz przeniesiony do linii, która spowodowała problem. Podczas gdy Xcode ... cóż ... daje taki ślad stosu. Nawet Turbo Pascal nie był taki przestarzały !!!
Mike Gledhill
4
To śmieszne, że firma, która rzekomo znana jest z „najlepszego doświadczenia użytkownika”, nie zdaje sobie sprawy z tego, że wszyscy programiści w ciągu ostatnich 20 lat są przyzwyczajeni do oglądania numeru wiersza, w którym zgłaszany jest wyjątek, a NIE W MONTAŻU. Czy oszaleję? Każdy język, którym pracowałem przez całe życie, podaje numery linii. Nawet C lub C ++.
mylovemhz