Dealing with Core Data “Phantom Breakpoints”
Anyone who has done extensive work with Core Data has no doubt run into the “Phantom Breakpoint” problem. This issue occurs when you add a Breakpoint in Xcode for “All Exceptions” and then find yourself being constantly trapped in the Debugger during normal Core Data usage – particularly when obtaining permanent managed object ID’s or saving the context. Continuing the from the breakpoint resumes program execution with no crash or other negative effect – despite the fact that an exception clearly was raised within Core Data.
Under the covers, what is happening is Core Data is using exceptions thrown via objc_exception_throw for control flow. The All Exceptions Breakpoint traps all exceptions on throw, including those that are never actually bubbled up to the application. These Breakpoints can become seriously annoying and greatly slow down your Xcode debugging session.
So how do we deal with this? It turns out to be pretty easy once you apply a little bit of LLDB kung-fu to inspect the exception:
- Remove your existing Breakpoint on “All Exceptions”
- Add a new Symbolic Breakpoint on objc_exception_throw
- Set the Condition on the Breakpoint to (BOOL)(! (BOOL)[[(NSException *)$eax className] hasPrefix:@“_NSCoreData”])
The condition will ignore any private Core Data exceptions (as determined by the class name being prefixed by _NSCoreData) that are used for control flow. Note that the $eax register is only correct for the iOS Simulator. On the Device, you’ll want to change the register to $r0 within the condition.
Note that this technique can be adapted easily to other conditionals. The tricky part was in crafting the BOOL and NSException casts to get lldb happy with the condition.
This question was asked and answered on Stack Overflow.