Making breakpoints work with single-line code blocks

Mar 7, 2023

When writing functional code we often run into situations where there are a lot of nested function calls. In many cases we want to compact the code, so that each function call is a single line. Take for instance this example, working with a combine publisher:

func observeName() {
    service.namePublisher()
        .map { $0.name }
        .filter { $0.name.contains("something") }
        .eraseToAnyPublisher()
}

When this code executes a breakpoint at any line here will only break once the function is called, and the publisher is set up. If you want to also the debugger to break whenever the map function is called you normally will have to reformat your code so that the $0.name statement falls on a separate line, and you can unambiguously tell the debugger that it's right there you want to break.

func observeName() {
    service.namePublisher()
        .map {
            $0.name  // breakpoint here
        }
        .filter { $0.name.contains("something") }
        .eraseToAnyPublisher()
}

This is far from ideal. Most importantly this forces you to actually stop your running app instance, and recompile with these code change for the debugger to start breaking inside the block. Secondly, this also leaves small code changes all over your code base, which you will have to come back and fix once you're done debugging.

There is, however a far better solution; column breakpoints. Column breakpoints are just like regular breakpoints, but you can enable them on nested blocks of code. To create one you simply right click at the statement you want to break on, and click Create column breakpoint. This creates a breakpoint at the beginning of the selected statement, and this breakpoint works just as a normal breakpoint does. You can right click it to pull up the context menu, double click to edit, or drag away to delete.