This is a rather quick post about running some arbitrary code inside result builders.

Result builders are great and often make the code much more readable — think SwiftUI vs UIKit… but builder blocks are quite strict about the types they expect to find so using arbitrary prints or calling other functions isn’t always easy, per sè.

I am often times a fan of inserting a print or two in the code, especially when I’m exploring new code. Sometimes stepping through all function calls is tedious and I’m really interested in just the sequence of execution of few interesting key code points…

I thought I’d share a function I’m using sometimes that makes “print debugging” with result builders easier:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
func printThrough<T>(
    _ t: T, 
    _ message: String? = nil, 
    map: ((T) -> String)? = nil
) -> T {
    let description = if let map {
        map(t)
    } else {
        String(describing: t)
    }

    let message = if let message {
        "\(message): '\(description)'"
    } else {
        description
    }

    print(message)

    return t
}

You can wrap a view in some SwiftUI code to print it like this:

1
2
3
4
5
HStack(alignment: .top) {
    printThrough(
        Text("Start")
    )
}

Or print an arbitrary message in some custom result builder like this:

1
2
3
4
5
6
7
Heading(level: 1) {
  Paragraph {
    printThrough(
      Div { }, map: { _ in "Custom message" }
    )
  }
}

Or even quickly inspect some of the wrapped type’s properties:

1
2
3
printThrough(
  BuyButton(), map: { "Message: \($0.title)" }
)

Or log some of this data in Instruments if you wanna visually see the logging sequence on a timeline:

1
2
3
4
5
6
7
printThrough(
    BuyButton(),
    map: {
        os_log(.debug, "Button:  %{public}@", $0.title)
        return $0.title
    }
)

It’s not a big thing and most builders will allow you to insert _ = print(...) but I still find it nice to wrap elements and do more than a simple print would.

Any thoughts on result builders and debugging?

Get in touch at https://mastodon.social/@icanzilb.