Missing dot from modifiers in SwiftUI causes runtime crash inside ViewBuilder

I've been teaching a SwiftUI course this week and a very common mistake from students is forgetting the dot when applying a modifier:

var body: some View {
        Text("Hello World")
            padding()
    }

This problem is quite difficult to notice, especially for beginners, because the code compiles normally but crashes during execution.

I understand that the code compiles because the modifier is being applied to self which returns a View but breaks during execution because there is a recursion.

Can someone with knowledge about resuilt builder explain to me what are the technical reasons for this behavior to be valid? I'm curious if this is something that we have to live with it or if it will be fixed eventually.

3 Likes

I think the technical reason is that otherwise something like this would not work:

struct ContentView: View {
    var body: some View {
        Text("Hello, world!")
        worldIcon()
    }

    func worldIcon() -> Image {
        Image(systemName: "globe")
    }
}

(This also works if you make worldIcon() an extension on View.)

So there is really no good way for the compiler to test whether such functions are modifies that could recurse or not.

1 Like

I think all SwiftUI View modifiers should be annotated with @warn_unqualified_access to prevent this kind of error. But for some reason the built-in ones are not. But you can do this for your own View modifiers you define. With @warn_unqualified_access, you cannot by mistake have a free standing modifier.

5 Likes

You already answered that question yourself: