/dev/trouble
Eric Roller's Development Blog

Re-running my unit tests on Xcode 9.4, I got stuck on an uncaught exception without any useful debug messages. All I got in the log was:

[...]
Test Case '-[AppTests.AppScriptTests testScriptFiles]' started.
libc++abi.dylib: terminating with uncaught exception of type NSException

and nothing more!

Certainly, I tried re-writing my Swift do-catch-blocks to be able to catch an NSException (Objective-C), but whichever catch line I added, it was never called.

I also tried stepping though the code in the debugger but since the test commands are read from a separate script, and code is spawned on separate threads, this is rather difficult. After trying for a couple of hours yesterday, I gave up.

Today, I remembered a different trick:

Adding an exception breakpoint.

In Xcode,

  1. open the Breakpoint Navigator (Cmd-8);
  2. scroll to the bottom and click "+";
  3. select "Exception Breakpoint…";
  4. since it was an NSException, I chose Exception: "Objective-C", Break: "On Throw", Action: (none);

With that exception breakpoint active, I could re-run my unit tests. There are quite a few legitimate exception throws in my project. For these, it was just a question of selecting "continue" in debugger until I finally landed on a line that was not meant to crash (the last command shown here):

if let allSelectedIndexPaths = self.tableView.indexPathsForSelectedRows {
    for selectedPath in allSelectedIndexPaths {
        self.tableView.deselectRow(at: selectedPath, animated: true)
    }

    self.tableView.reloadRows(at: [ allSelectedIndexPaths ], with: .automatic)
}

So what is wrong with this code?

Answer: A different thread had removed rows from the table view, resulting in me trying to refresh non-existing rows.