Ich habe einen Haltepunkt für alle Ausnahmen in Xcode konfiguriert:
Manchmal stoppt Xcode in einer Zeile wie:
[managedObjectContext save:&error];
mit folgender Rückverfolgung:
Das Programm wird jedoch fortgesetzt, als wäre nichts passiert, wenn Sie auf Weiter klicken.
Wie kann ich diese "normalen" Ausnahmen ignorieren und den Debugger trotzdem für Ausnahmen in meinem eigenen Code stoppen lassen?
(Ich verstehe, dass dies geschieht, weil Core Data intern Ausnahmen auslöst und abfängt und dass Xcode einfach meiner Aufforderung nachkommt, das Programm anzuhalten, wenn eine Ausnahme ausgelöst wird. Ich möchte diese jedoch ignorieren, damit ich wieder meinen eigenen Code debuggen kann !)
Moderatoren: Dies ähnelt der "Xcode 4-Ausnahme-Breakpoint-Filterung" , aber ich denke, diese Frage dauert zu lange, um auf den Punkt zu kommen, und hat keine nützlichen Antworten. Können sie verknüpft werden?
Antworten:
Ich habe ein lldb-Skript geschrieben, mit dem Sie Objective-C-Ausnahmen mit einer viel einfacheren Syntax selektiv ignorieren können. Es behandelt sowohl OS X, iOS Simulator als auch 32-Bit- und 64-Bit-ARM.
Installation
~/Library/lldb/ignore_specified_objc_exceptions.py
oder an einem nützlichen Ort ein.import lldb import re import shlex # This script allows Xcode to selectively ignore Obj-C exceptions # based on any selector on the NSException instance def getRegister(target): if target.triple.startswith('x86_64'): return "rdi" elif target.triple.startswith('i386'): return "eax" elif target.triple.startswith('arm64'): return "x0" else: return "r0" def callMethodOnException(frame, register, method): return frame.EvaluateExpression("(NSString *)[(NSException *)${0} {1}]".format(register, method)).GetObjectDescription() def filterException(debugger, user_input, result, unused): target = debugger.GetSelectedTarget() frame = target.GetProcess().GetSelectedThread().GetFrameAtIndex(0) if frame.symbol.name != 'objc_exception_throw': # We can't handle anything except objc_exception_throw return None filters = shlex.split(user_input) register = getRegister(target) for filter in filters: method, regexp_str = filter.split(":", 1) value = callMethodOnException(frame, register, method) if value is None: output = "Unable to grab exception from register {0} with method {1}; skipping...".format(register, method) result.PutCString(output) result.flush() continue regexp = re.compile(regexp_str) if regexp.match(value): output = "Skipping exception because exception's {0} ({1}) matches {2}".format(method, value, regexp_str) result.PutCString(output) result.flush() # If we tell the debugger to continue before this script finishes, # Xcode gets into a weird state where it won't refuse to quit LLDB, # so we set async so the script terminates and hands control back to Xcode debugger.SetAsync(True) debugger.HandleCommand("continue") return None return None def __lldb_init_module(debugger, unused): debugger.HandleCommand('command script add --function ignore_specified_objc_exceptions.filterException ignore_specified_objc_exceptions')
Fügen Sie Folgendes hinzu zu
~/.lldbinit
:command script import ~/Library/lldb/ignore_specified_objc_exceptions.py
Ersetzen
~/Library/lldb/ignore_specified_objc_exceptions.py
durch den richtigen Pfad, wenn Sie ihn an einem anderen Ort gespeichert haben.Verwendung
ignore_specified_objc_exceptions name:NSAccessibilityException className:NSSomeException
NSException
-name
ÜbereinstimmungenNSAccessibilityException
ODER-className
Übereinstimmungen vorliegenNSSomeException
Es sollte ungefähr so aussehen:
In Ihrem Fall würden Sie verwenden
ignore_specified_objc_exceptions className:_NSCoreData
Unter http://chen.do/blog/2013/09/30/selectively-ignoring-objective-c-exceptions-in-xcode/ finden Sie das Skript und weitere Details.
quelle
Bei Kerndatenausnahmen entferne ich normalerweise den Haltepunkt "Alle Ausnahmen" aus Xcode und stattdessen:
objc_exception_throw
(BOOL)(! (BOOL)[[(NSException *)$x0 className] hasPrefix:@"_NSCoreData"])
Der konfigurierte Haltepunkt sollte ungefähr so aussehen:
Dadurch werden alle privaten Core Data-Ausnahmen (die durch den vorangestellten Klassennamen bestimmt werden) ignoriert
_NSCoreData
, die für den Kontrollfluss verwendet werden. Beachten Sie, dass das entsprechende Register von dem Zielgerät / Simulator abhängt, in dem Sie ausgeführt werden. Schauen Sie sich diese Tabelle als Referenz an.Beachten Sie, dass diese Technik leicht an andere Bedingungen angepasst werden kann. Der schwierige Teil bestand darin, die BOOL- und NSException-Casts herzustellen, um lldb mit der Bedingung zufrieden zu stellen.
quelle
$r0
:(BOOL)(! (BOOL)[[(NSException *)$r0 className] hasPrefix:@”_NSCoreData”])
. Dies funktioniert jedoch nicht. Ich bekomme folgendes in der Konsole.Stopped due to an error evaluating condition of breakpoint 1.1: "(BOOL)(! (BOOL)[[(NSException *)$r0 className] hasPrefix:@”_NSCoreData”])" error: unexpected '@' in program error: 1 errors parsing expression
currentName
Selektor hat mir nicht gefallen . Es zu[(NSException *)$eax name]
ändern hat für mich funktioniert.$r0
um$x0
(wie hier definiert: sealiesoftware.com/blog/archive/2013/09/12/... ). Die Bedingung wird somit:(BOOL)(! (BOOL)[[(NSException *)$x0 className] hasPrefix:@"_NSCoreData"])
Hier ist eine alternative schnelle Antwort, wenn Sie einen Codeblock haben, z. B. eine Bibliothek des 3. Teils, die mehrere Ausnahmen auslöst, die Sie ignorieren möchten:
Dies bedeutet, dass es sich um Haltepunkt 2 handelt. Bearbeiten Sie nun in xcode den ersten Haltepunkt (vor dem Auslösecode für Ausnahmen) und ändern Sie die Aktion in "Debugger-Befehl". Geben Sie "Haltepunkt deaktivieren 2" ein (und aktivieren Sie das Kontrollkästchen "Automatisch fortfahren ...") ).
Machen Sie dasselbe für den Haltepunkt nach der fehlerhaften Linie und lassen Sie den Befehl 'Haltepunkt aktivieren 2'.
Die Ausnahme für alle Haltepunkte wird jetzt ein- und ausgeschaltet, sodass sie nur dann aktiv ist, wenn Sie sie benötigen.
quelle