web-dev-qa-db-ger.com

Auf EXC_BAD_ACCESS in XCode abbrechen?

Ich bin neu in iPhone-Entwicklung und XCode im Allgemeinen und habe keine Ahnung, wie mit der Fehlerbehebung für ein EXC_BAD_ACCESS-Signal begonnen werden soll. Wie kann ich XCode dazu bringen, genau an der Zeile zu brechen, die den Fehler verursacht?


Ich kann nicht scheinen, dass XCode in der Zeile angehalten wird, die das Problem verursacht, aber ich sehe die folgenden Zeilen in meiner Debug-Konsole:

So Okt 25 15:12:14 jasonsmacbook Testprojekt [1289]: CGContextSetStrokeColorWithColor: ungültiger Kontext

So Okt 25 15:12:14 jasonsmacbook Testprojekt [1289]: CGContextSetLineWidth: ungültiger Kontext

So Okt 25 15:12:14 jasonsmacbook Testprojekt [1289]: CGContextAddPath: ungültiger Kontext

So Okt 25 15:12:14 jasonsmacbook Testprojekt [1289]: CGContextDrawPath: ungültiger Kontext

2009-10-25 15: 12: 14.680 LanderTest [1289: 207] *** - [CFArray objectAtIndex:]: Nachricht wurde an .__ gesendet. freigegebene Instanz 0x3c4e610

Jetzt versuche ich, auf den Kontext zu zeichnen, den ich von UIGraphicsGetCurrentContext() abrufe, und das Objekt zu übergeben, mit dem ich zeichnen möchte.


Weiteres Debuggen von Versuchen und Fehlern. Ich fand heraus, dass eine NSMutableArray, für die ich eine Eigenschaft in meiner Klasse habe, ein Zombie war. Ich ging in die init-Funktion für die Klasse und hier ist der Code, den ich verwendete:

if ((self = [super init])) {
        NSMutableArray *array = [NSMutableArray array];
        self.terrainBlocks = array;
        [array release];
    }
    return self;    
}

Ich habe die [array release]-Leitung entfernt und es gibt mir nicht mehr das EXC_BAD_ACCESS-Signal, aber ich bin jetzt verwirrt, warum dies funktioniert. Ich dachte, wenn ich die Eigenschaft benutzte, behielt sie es automatisch für mich und daher sollte ich es aus init herausgeben, damit ich kein Leck habe. Ich bin völlig verwirrt, wie dies funktioniert, und alle Anleitungen und Stackoverflow-Fragen, die ich gelesen habe, verwirren mich mehr darüber, wie Sie Eigenschaften in meiner init-Methode festlegen. Es scheint keinen Konsens zu geben, welcher Weg der beste ist.

45
jasonh

Bei allen EXC_BAD_ACCESS-Fehlern versuchen Sie normalerweise, eine Nachricht an ein freigegebenes Objekt zu senden. Der BEST Weg, um diese herauszufinden, ist use NSZombieEnabled .

Dies funktioniert, indem ein Objekt nie wirklich freigegeben wird, sondern indem es als "Zombie" zusammengefasst wird und ein Flag gesetzt wird, das besagt, dass es normalerweise freigegeben worden wäre. Wenn Sie versuchen, erneut darauf zuzugreifen, wissen Sie immer noch, was es war, bevor Sie den Fehler gemacht haben. Mit dieser kleinen Information können Sie in der Regel zurückgehen, um zu sehen, was das Problem war.

Dies ist insbesondere in Hintergrundthreads hilfreich, wenn der Debugger manchmal nützliche Informationen enthält.

Sehr wichtig zu beachten ist jedoch, dass Sie zu 100% sicherstellen müssen, dass dies nur in Ihrem Debug-Code und nicht in Ihrem Verteilungscode enthalten ist. Da nie etwas veröffentlicht wird, läuft Ihre App undicht. Um mich daran zu erinnern, füge ich dieses Protokoll in meinem Appdelegate ein:

if(getenv("NSZombieEnabled") || getenv("NSAutoreleaseFreedObjectCheckEnabled"))
  NSLog(@"NSZombieEnabled/NSAutoreleaseFreedObjectCheckEnabled enabled!");

Wenn Sie Hilfe beim Ermitteln der genauen Zeile benötigen, führen Sie ein Build-and-Debug (CMD-Y) anstelle eines Build-and-Run (CMD-R) aus. Wenn die App abstürzt, zeigt Ihnen der Debugger genau, welche Zeile und in Kombination mit NSZombieEnabled genau wissen, warum.

84
coneybeare

Über Ihr Array Die Linie 

NSMutableArray *array = [NSMutableArray array];

gibt Ihnen eigentlich kein zurückbehaltenes Objekt, sondern eher ein Objekt zur automatischen Freigabe. Es wird wahrscheinlich in der nächsten Zeile beibehalten, aber Sie sollten es nicht in der dritten Zeile freigeben. Siehe this

Dies ist die Grundregel:

Sie übernehmen das Eigentum an einem Objekt, wenn Sie es mit einer Methode erstellen, deren Name mit "Allocate" oder "New" beginnt oder "Copy" enthält (z. B. Allocat, NewObject oder MutableCopy) oder wenn Sie ihm eine Aufbewahrungsmeldung senden. Sie sind dafür verantwortlich, dass Sie das Eigentum an Objekten, die Sie besitzen, durch Freigabe oder Autorelease aufgeben. Wenn Sie ein Objekt zu einem anderen Zeitpunkt erhalten, dürfen Sie es nicht freigeben.

17
epatel

In Xcode 4 können Sie Zombies aktivieren, indem Sie auf das Dropdown-Menü Schema (oben links, rechts neben der Schaltfläche Stopp) klicken -> Schema bearbeiten -> Registerkarte Diagnose -> Zombie-Objekte aktivieren

10
snez

Xcode/gdb bricht immer bei EXC_BAD_ACCESS ab, Sie müssen lediglich den Aufrufstapel hocharbeiten, um den Code zu finden, der ihn ausgelöst hat. 

Beachten Sie, dass diese Art von Fehlern häufig bei autoreleased-Objekten auftritt, was bedeutet, dass die Ursache des Problems nicht in der Aufrufliste liegt, die EXC_BAD_ACCESS ausgelöst hat. In diesem Fall werden NSZombieEnabled und NSAutoreleaseFreedObjectCheckEnabled hilfreich.

7
Darren

Eine neue Antwort auf einen alten Thread ... In XCode 4 ist der effektivste Weg zur Diagnose von EXC_BAD_ACCESS-Ausnahmen die Verwendung von Instrumenten zum Profilieren Ihrer App (klicken Sie in XCode auf Produkt/Profil und wählen Sie Zombies). Auf diese Weise können Sie Nachrichten identifizieren, die an freigegebene Objekte gesendet wurden.

5

Von den Stanford CS193P-Klassen aus: Wenn Sie einen Haltepunkt (manuell, durch Bearbeiten von Haltepunkten) für das Symbolobjc_exception_throw hinzufügen, erhalten Sie ein viel besseres Bild von dem, was falsch gelaufen ist. Lassen Sie die Dinge bis zu dem Punkt weitergehen, an dem der Debugger anhält und dazu neigt, Dinge zu verdunkeln Verschrauben Sie die Stapelspur. Wenn Sie in objc_exception_throw anhalten, können Sie oft zurückschauen, welche Zugriffe/Vorgänge Ihr Problem verursacht haben.

2
Adam Eberbach

Ein weiterer hilfreicher Ansatz ist das Setzen von Haltepunkten, die direkt nach Auftreten der Ausnahme ausgelöst werden:

Öffnen Sie das Haltepunktfenster (Ausführen - Zeigen - Haltepunkte) und fügen Sie zwei symbolische Haltepunkte mit den Namen "objc_exception_throw" und "[NSException raise]" hinzu. 

Von: http://blog.emmerinc.be/index.php/2009/03/19/break-on-exception-in-xcode/

2
Frank

Ich wollte nur für die anderen hinzufügen, die aus einem Web kommen, und nach Lösungen für den gleichen Fehler suchen, aber mit unterschiedlichen Fehlern. In meinem Fall erhielt ich die gleiche Fehlermeldung, als ich versuchte, NSDictionary mit einem Tippfehler im Schlüsselnamen zu instanziieren, wobei ich vergaß, "@" vor meinem Schlüssel hinzuzufügen:

NSDictionary *dic = [NSDictionary dictionaryWithObjectsAndKeys: myObj1, @"goodKey", myObj2, "badkey @ is missing in front", nil];
1
Centurion

Ich hoffe, ich habe keine identische Antwort verpasst, aber ich habe festgestellt, dass es für einige Projekte möglich ist, diesen Fehler auszulösen, da Simulatoren für ältere iOS-Versionen ausgeführt werden, die möglicherweise mit einer Projektabhängigkeit oder einem Framework nicht kompatibel sind. Ich jagte eine davon zu lange, bevor mir klar wurde, dass dies nur in den älteren Simulator-Versionen vorkam, wie beispielsweise mit dem iPhone 4S. Die App sollte eigentlich nicht versuchen, sie zu unterstützen.

Es wäre schön gewesen, eine ausführlichere Fehlermeldung erhalten zu haben, aber ich könnte mir vorstellen, dass dies in der Verantwortung des Frameworks liegt, in dem es entstanden ist wie ich mich fand.

1

Bevor Sie Zombies aktivieren, sollten Sie zunächst alle Warnungen (falls vorhanden) entfernen. Einfache Dinge wie eine nicht leere Funktion ohne return können diesen Fehler verursachen. Wenn Sie keine Warnungen haben, fahren Sie mit den anderen Antworten fort.

0
user2387149