iphone - developpement - Ignorer certaines exceptions lors de l'utilisation du point d'arrêt Toutes les exceptions de Xcode



développement ios swift (2)

J'ai un point d'arrêt All Exceptions configuré dans Xcode:

Parfois, Xcode s'arrêtera sur une ligne comme:

[managedObjectContext save:&error];

avec le backtrace suivant:

mais le programme continue comme si rien ne se passait si vous cliquez sur Continuer.

Comment puis-je ignorer ces exceptions "normales", mais toujours le débogueur s'arrête sur des exceptions dans mon propre code?

(Je comprends que cela arrive parce que Core Data jette et attrape en interne des exceptions, et que Xcode est simplement en train d'honorer ma demande de mettre le programme en pause quand une exception est levée, mais je veux les ignorer pour pouvoir déboguer mon propre code !)

Modérateurs: ceci est similaire à "Xcode 4 exception breakpoint filtering" , mais je pense que cette question prend trop de temps pour se rendre au point et n'a pas de réponses utiles. Peuvent-ils être liés?


Answer #1

J'ai écrit un script lldb qui vous permet d'ignorer sélectivement les exceptions Objective-C avec une syntaxe beaucoup plus simple, et il gère à la fois OS X, iOS Simulator, et à la fois 32 bits et 64 bits ARM.

Installation

  1. Placez ce script dans ~/Library/lldb/ignore_specified_objc_exceptions.py ou quelque part utile.
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. Ajoutez ce qui suit à ~/.lldbinit :

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

    en remplaçant ~/Library/lldb/ignore_specified_objc_exceptions.py par le bon chemin si vous l'avez sauvegardé ailleurs.

Usage

  • Dans Xcode, ajoutez un point d'arrêt pour capturer toutes les exceptions Objective-C
  • Modifiez le point d'arrêt et ajoutez une commande de débogueur avec la commande suivante: ignore_specified_objc_exceptions name:NSAccessibilityException className:NSSomeException
  • Cela ignorera les exceptions où NSException -name correspond à NSAccessibilityException OU -className correspond à NSSomeException

Ça devrait ressembler a quelque chose comme ca:

Dans votre cas, vous utiliseriez ignore_specified_objc_exceptions className:_NSCoreData

Voir http://chen.do/blog/2013/09/30/selectively-ignoring-objective-c-exceptions-in-xcode/ pour le script et plus de détails.


Answer #2

Pour les exceptions de données de base, ce que je fais généralement est de supprimer le point d'arrêt "Toutes les exceptions" de Xcode et à la place:

  1. Ajouter un point d'arrêt symbolique sur objc_exception_throw
  2. Définir une condition sur le point d'arrêt à (BOOL)(! (BOOL)[[(NSException *)$x0 className] hasPrefix:@"_NSCoreData"])

Le point d'arrêt configuré doit ressembler à ceci:

Cela ignore toutes les exceptions de données de base privées (telles que déterminées par le nom de classe précédé par _NSCoreData ) qui sont utilisées pour le flux de contrôle. Notez que le registre approprié dépendra du périphérique / simulateur cible que vous utilisez. Consultez cette table pour référence.

Notez que cette technique peut être facilement adaptée à d'autres conditions. La partie la plus délicate a été d'élaborer les lancers BOOL et NSException pour que lldb soit satisfait de la condition.





xcode