Ignorieren Sie bestimmte Ausnahmen, wenn Sie den Haltepunkt Alle Ausnahmen von Xcode verwenden

78

Ich habe einen Haltepunkt für alle Ausnahmen in Xcode konfiguriert:

Screenshot eines in Xcode Breakpoint Pain konfigurierten Ausnahme-Haltepunkts, der so konfiguriert ist, dass beim Auslösen einer Ausnahme ein Ton ausgegeben wird

Manchmal stoppt Xcode in einer Zeile wie:

[managedObjectContext save:&error];

mit folgender Rückverfolgung:

Backtrace zeigt NSPersistentStoreCoordinator, der eine Ausnahme innerhalb des Aufrufs auslöst, um zu speichern:

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?

Phil Calvin
quelle
Können Sie "bestimmte Ausnahmen" klarer formulieren?
Jesse Rusak
Argh, sorry! Stapelüberlauf gepostet, bevor ich fertig war (versehentlich die Eingabetaste im Feld Tags drücken). Ich werde ihn bearbeiten. = (
Phil Calvin
Dies scheint genau die gleiche Frage zu sein wie die andere. Wie wäre es, es zu schließen und ein Kopfgeld auf das andere zu setzen? Sie können dem anderen auch eine Bearbeitung vorschlagen, um sie zu bereinigen, wenn Sie der Meinung sind, dass dies unklar ist.
Jesse Rusak

Antworten:

41

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

  1. Fügen Sie dieses Skript in ~/Library/lldb/ignore_specified_objc_exceptions.pyoder 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')
  1. Fügen Sie Folgendes hinzu zu ~/.lldbinit:

    command script import ~/Library/lldb/ignore_specified_objc_exceptions.py

    Ersetzen ~/Library/lldb/ignore_specified_objc_exceptions.pydurch den richtigen Pfad, wenn Sie ihn an einem anderen Ort gespeichert haben.

Verwendung

  • Fügen Sie in Xcode einen Haltepunkt hinzu, um alle Objective-C- Ausnahmen abzufangen
  • Bearbeiten Sie den Haltepunkt und fügen Sie einen Debugger-Befehl mit dem folgenden Befehl hinzu: ignore_specified_objc_exceptions name:NSAccessibilityException className:NSSomeException
  • Dies ignoriert Ausnahmen, bei denen NSException -nameÜbereinstimmungen NSAccessibilityExceptionODER -classNameÜbereinstimmungen vorliegenNSSomeException

Es sollte ungefähr so ​​aussehen:

Screenshot mit einem in Xcode gemäß den Anweisungen festgelegten Haltepunkt

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.

Chendo
quelle
Das funktioniert wirklich gut für mich. Wären Sie bereit, Ihre Skript- und Installationsanweisungen direkt zu Stack Overflow beizutragen (und sie somit als cc-wiki zu lizenzieren ?). Wenn ja, werde ich diese Antwort akzeptieren!
Phil Calvin
Ich hätte @chendo in dieser letzten Antwort markieren sollen.
Phil Calvin
@PhilCalvin Wäre eine Lizenzierung als MIT besser?
Chendo
1
Funktioniert super. Nur um es noch einmal zu betonen - Sie müssen den Haltepunkt auf "Objective-C" setzen, da hier auch eine C ++ - Ausnahme ausgelöst wird.
Matej Bukovinski
1
Funktioniert sehr gut in Xcode 5.1. Ein wichtiges Detail: Sie müssen Objective-C als Ausnahmetyp auswählen (wie in der Anleitung erwähnt)
Phil Calvin
87

Bei Kerndatenausnahmen entferne ich normalerweise den Haltepunkt "Alle Ausnahmen" aus Xcode und stattdessen:

  1. Fügen Sie einen symbolischen Haltepunkt hinzu objc_exception_throw
  2. Setzen Sie eine Bedingung für den Haltepunkt auf (BOOL)(! (BOOL)[[(NSException *)$x0 className] hasPrefix:@"_NSCoreData"])

Der konfigurierte Haltepunkt sollte ungefähr so ​​aussehen: Haltepunkt konfigurieren

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.

Blake Watters
quelle
Sehr hilfreich, insbesondere wenn Core Data für mehrere Threads verwendet wird und diese falschen Ausnahmen viel häufiger ausgelöst werden! Vielen Dank!
Meister
1
Ich versuche dies auf dem Gerät mit $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
Lammert
@lammert Vielleicht möchten Sie die Anführungszeichen, die Sie aus dem Beispiel kopiert haben, durch tatsächliche Anführungszeichen ersetzen. Der Inhalt, den Sie kopiert haben, enthält hübsche Zitate.
Jeremy Foo
Ich habe es gerade in Xcode 4.6.3 (4H1503) versucht, und der currentNameSelektor hat mir nicht gefallen . Es zu [(NSException *)$eax name]ändern hat für mich funktioniert.
Adam Sharp
4
Xcode 6.2 mit iOS 8.2 auf iPhone6 erforderlich mich das zu ändern , $r0um $x0(wie hier definiert: sealiesoftware.com/blog/archive/2013/09/12/... ). Die Bedingung wird somit:(BOOL)(! (BOOL)[[(NSException *)$x0 className] hasPrefix:@"_NSCoreData"])
Wim Fikkert
16

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:

  1. Setzen Sie zwei Haltepunkte, einen vor und einen nach dem Codeblock, den Sie ignorieren möchten.
  2. Führen Sie das Programm aus, bis es an einer Ausnahme stoppt, und geben Sie "Haltepunktliste" in die Debugger-Konsole ein. Suchen Sie die Nummer des Haltepunkts "Alle Ausnahmen". Es sollte folgendermaßen aussehen:

2: names = {'objc_exception_throw', '__cxa_throw'}, location = 2 Optionen: deaktiviert 2.1: where = libobjc.A.dylib objc_exception_throw, address = 0x00007fff8f8da6b3, unresolved, hit count = 0 2.2: where = libc++abi.dylib__cxa_throw, address = 0x00007fff8d19fab7, ungelöst, hit count = 0

  1. 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 ...") ).

  2. 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.

james_alvarez
quelle
Danke! genau das, wonach ich gesucht habe. Obwohl ich die Ausnahme-ID nicht finden konnte - nur brutal erzwungen. Können Sie diesen Teil genauer beschreiben? Ich meine, wo genau in Xcode diese 'Haltepunktliste' einfügen, um die Haltepunkt-ID / Position zu sehen?
Vir uns
Tolle! Funktioniert wie Charme!
Sergey Grischyov
1
Hervorragend - diese Lösung ist viel einfacher als einige der anderen Antworten und funktioniert perfekt.
Ajgryc
Brillant! Dies ist ein Juwel einer SO-Antwort und sollte die akzeptierte sein.
jb