使用Xcode的“所有exception”断点时,请忽略某些exception
我有在Xcode中configuration的所有exception断点:
有时Xcode会停在一行,如:
[managedObjectContext save:&error];
跟着下面的回溯:
但程序继续,如果您点击继续,就好像什么也没有发生。
我怎么能忽略这些“正常”的exception,但仍然有我的代码中的exception停止debugging器?
(我知道这是因为Core Data在内部引发并捕获exception,而且Xcode只是简单地遵守我的请求来暂停程序,但是,我想忽略这些,所以我可以回到debugging我自己的代码!)
版主:这与“Xcode 4exception断点过滤”类似,但我认为这个问题需要很长的时间来解决,并没有任何有用的答案。 他们能联系起来吗?
我写了一个lldb脚本,可以让你select性地忽略Objective-Cexception,并且可以处理OS X,iOS Simulator以及32位和64位ARM。
安装
- 把这个脚本放在
~/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'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')
-
将以下内容添加到
~/.lldbinit
:command script import ~/Library/lldb/ignore_specified_objc_exceptions.py
用正确的pathreplace
~/Library/lldb/ignore_specified_objc_exceptions.py
,如果你把它保存在别的地方的话。
用法
- 在Xcode中,添加一个断点来捕获所有的Objective-Cexception
- 编辑断点并使用以下命令添加Debugger命令:
ignore_specified_objc_exceptions name:NSAccessibilityException className:NSSomeException
- 这将忽略
NSException
-name
匹配NSAccessibilityException
或-className
匹配NSSomeException
它应该看起来像这样:
在你的情况下,你可以使用ignore_specified_objc_exceptions className:_NSCoreData
有关脚本和更多详细信息,请参阅http://chen.do/blog/2013/09/30/selectively-ignoring-objective-c-exceptions-in-xcode/ 。
对于核心数据exception,我通常所做的是从Xcode中删除“所有exception”断点,而不是:
- 在
objc_exception_throw
上添加一个符号断点 - 将断点上的条件设置为
(BOOL)(! (BOOL)[[(NSException *)$x0 className] hasPrefix:@"_NSCoreData"])
configuration的断点看起来应该像这样:
这将忽略用于控制stream的任何专用核心数据exception(由类名前缀_NSCoreData
)。 请注意,相应的寄存器将取决于您正在运行的目标设备/模拟器。请参阅此表以供参考。
请注意,这种技术可以很容易地适应其他条件。 棘手的部分是在制定BOOL和NSException投标,以获得满意的条件。
这里有一个替代的快速答案,当你有一个代码块,例如一个第三方库引发你想忽略的多个exception:
- 设置两个断点,一个在你想忽略的exception抛出代码块之前和之后一个。
-
运行程序,直到它停在一个exception处,然后在debugging器控制台中input“断点列表”,find“所有exception”断点的编号,它应该是这样的:
2:names = {'objc_exception_throw','__cxa_throw'},locations = 2 Options:disabled 2.1:where = libobjc.A.dylib
objc_exception_throw, address = 0x00007fff8f8da6b3, unresolved, hit count = 0 2.2: where = libc++abi.dylib
__cxa_throw,地址= 0x00007fff8d19fab7,未解决,命中计数= 0 -
这意味着它是断点2.现在在xcode中,编辑第一个断点(在exception抛出代码之前),并将操作更改为“debugger command”并键入“断点禁用2”(并设置“自动继续…”checkbox)。
-
在违规行之后的断点处执行相同的操作,并执行命令“断点使能2”。
所有的断点exception现在会打开和closures,所以它只在需要时才会激活。