In the previous video, we used the Swift error breakpoint to suspend the process of the app if an error is thrown in your code or the code of a library or framework. The exception breakpoint works in a similar way. The difference, as you may have guessed, is that the debugger suspends the process of the app if an exception is thrown.

Breaking on Exceptions

Open the project we created in the previous video. In ContentView.swift, we declare a struct with name User. The struct defines two properties, firstName of type String and lastName of type String.

struct User {

    let firstName: String
    let lastName: String

}

Let's trigger an exception by creating a User object and storing it in the user defaults database. We remove the body of the task and create a User object.

.task {
    let user = User(firstName: "Bart", lastName: "Jacobs")
}

We store the User object in the user defaults database by passing it to the setValue(_:forKey:) method of the UserDefaults class. We pass a string literal as the second argument, the key.

.task {
    let user = User(
        firstName: "Bart",
        lastName: "Jacobs"
    )

    UserDefaults.standard.setValue(
        user,
        forKey: "currentUser"
    )
}

Run the app to see what happens if we attempt to store a User object in the user defaults database. The app is terminated soon after launching. It seems as if the debugger has suspended the process of the app in the BreakpointsApp struct. But notice that the instruction pointer is red, not green. The red instruction pointer indicates that the process of the app was terminated due to a fatal error.

The app is terminated.

The output in Xcode's console is more helpful. It shows us that an NSInvalidArgumentExcpetion was thrown by Core Foundation. That is what caused the app to be terminated. Remember that you can only store property list objects in the user defaults database.

Attempt to set a non-property-list object Breakpoints.User(firstName: "Bart", lastName: "Jacobs") as an NSUserDefaults/CFPreferences value for key currentUser
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Attempt to insert non-property list object Breakpoints.User(firstName: "Bart", lastName: "Jacobs") for key currentUser'
...

libc++abi: terminating due to uncaught exception of type NSException

Let me show you how an exception breakpoint can help you debug issues like this. Open the Breakpoint Navigator, click the + button in the lower left, and choose Exception Breakpoint. Xcode offers us several options. We can choose which exceptions we want the debugger to break on, Objective-C exceptions, C++ exceptions, or both.

Adding an exception breakpoint.

We can also configure when the debugger should suspend the process, when the exception is thrown or when it is caught.

Adding an exception breakpoint.

Set Exception to Objective-C and set Break to On Throw.

Adding an exception breakpoint.

Run the app to see what happens. This time the app isn't terminated. The instruction pointer is green, not red. The debugger suspends the process of the app in ContentView.swift. Because we try to store a non-property list object in the user defaults database, Core Foundation throws an exception. The instruction pointer points to the line of code that triggered the exception and that is what we want. The stack trace is also helpful, taking us to the root of the problem.

The app breaks on an exception being thrown.

Setting an exception breakpoint won't change the outcome of the code we wrote, but it gives us more context to debug the problem. Without the exception breakpoint set, the app crashes. We can put the pieces together by inspecting the output in Xcode's console.

With the exception breakpoint set, however, the debugger suspends the process of the the app the moment the exception is thrown. The debugger breaks the process on the offending line in the task. That gives us more information and options to further debug the issue.

Even though the app is written entirely in Swift, the Foundation and Core Foundation frameworks are written in C and Objective-C. When something goes haywire, an exception is thrown.

What's Next

Swift error and exception breakpoints are indispensable at times. In most of my projects, the exception breakpoint is always enabled because it makes debugging problems related to the incorrect use of Apple's frameworks much easier.

The Swift error breakpoint enables you to quickly find out where an error is thrown, taking you to the root of the problem. It saves you time and adds clarity when debugging.