Подтвердить что ты не робот

Игнорировать некоторые исключения при использовании точки останова Xcode All Exceptions

У меня есть контрольная точка All Exceptions, настроенная в Xcode:

screenshot of an exception breakpoint configured in Xcode breakpoint pain, configured to make a sound when an exception is thrown

Иногда Xcode останавливается на строке, например:

[managedObjectContext save:&error];

со следующей обратной трассировкой:

backtrace showing NSPersistentStoreCoordinator throwing an exception inside the call to save:

но программа продолжается, как будто ничего не произошло, если вы нажмете "Продолжить".

Как я могу игнорировать эти "нормальные" исключения, но все еще есть отладчик останавливается на исключениях в моем собственном коде?

(Я понимаю, что это происходит из-за того, что Core Data внутренне выбрасывает и ловит исключения, и что Xcode просто выполняет мой запрос на приостановку программы всякий раз, когда генерируется исключение. Однако я хочу игнорировать их, чтобы вернуться к отладке мой собственный код!)

Модераторы: это похоже на "фильтрацию контрольных точек исключения Xcode 4" , но я думаю, что этот вопрос занимает слишком много времени, чтобы обойти точку и не иметь любые полезные ответы. Могут ли они быть связаны?

4b9b3361

Ответ 1

Я написал lldb script, который позволяет выборочно игнорировать исключения Objective-C с гораздо более простым синтаксисом и обрабатывает как OS X, iOS Simulator, так и 32-битную и 64-битную ARM.

Установка

  • Поместите этот script в ~/Library/lldb/ignore_specified_objc_exceptions.py или где-нибудь полезный.
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 {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. Добавьте в ~/.lldbinit следующее:

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

    заменив ~/Library/lldb/ignore_specified_objc_exceptions.py на правильный путь, если вы сохранили его где-то еще.

Использование

  • В Xcode добавьте точку останова, чтобы поймать все Objective-C исключения
  • Отредактируйте точку останова и добавьте команду отладчика с помощью следующей команды: ignore_specified_objc_exceptions name:NSAccessibilityException className:NSSomeException
  • Это игнорирует исключения, в которых NSException -name соответствует NSAccessibilityException ИЛИ -className соответствует NSSomeException

Он должен выглядеть примерно так:

Screenshot showing a breakpoint set in Xcode per the instructions

В вашем случае вы должны использовать ignore_specified_objc_exceptions className:_NSCoreData

Смотрите http://chen.do/blog/2013/09/30/selectively-ignoring-objective-c-exceptions-in-xcode/ для script и более подробной информации.

Ответ 2

Для исключений Core Data то, что я обычно делаю, это удалить контрольную точку "Все исключения" из Xcode и вместо этого:

  • Добавить символическую точку останова на objc_exception_throw
  • Установите условие на точку останова на (BOOL)(! (BOOL)[[(NSException *)$x0 className] hasPrefix:@"_NSCoreData"])

Конфигурированная точка останова должна выглядеть примерно так: Configuring the Breakpoint

Это игнорирует любые частные исключения Core Data (как определено именем класса, префиксом которого является _NSCoreData), которые используются для потока управления. Обратите внимание, что соответствующий регистр будет зависеть от целевого устройства/симулятора, в котором вы работаете. Просмотрите эту таблицу для справки.

Обратите внимание, что этот метод легко адаптируется к другим условностям. Трудная часть заключалась в создании броуновских и NSException, чтобы получить lldb довольным условием.

Ответ 3

Вот альтернативный быстрый ответ, когда у вас есть блок кода, например. библиотека 3-й части, которая выдает несколько исключений, которые вы хотите игнорировать:

  • Задайте две точки останова: одну до и одну после исключения, бросающую блок кода, который вы хотите игнорировать.
  • Запустите программу, пока она не остановится при исключении, и введите "список контрольных точек" в консоль отладчика и найдите номер точки останова "все исключения", он должен выглядеть следующим образом:

2: names = {'objc_exception_throw', '__cxa_throw'}, locations = 2 Опции: отключено  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, unresolved, hit count = 0

  1. Это означает, что это точка останова 2. Теперь в xcode отредактируйте первую точку останова (перед кодом исключения) и измените действие на команду "отладчик" и введите "breakpoint disable 2" (и установите "автоматически" continue... ').

  2. Сделайте то же самое для точки останова после строки нарушения и получите команду "точка останова 2".

Все исключения контрольных точек теперь включаются и выключаются, поэтому они активны только тогда, когда вам это нужно.