Why some SwiftUI views have body = Swift.Never

Hi There,

I was wondering if someone can shed some light around this:
1- why some SwiftUI Views have body = Swift.Never.
2- is there a general rule for that? for example List().body = Swift.Never, while Button().body is not.
3- Also, by the same token, why in struct _ViewModifier_Content below, the struct needed to have body == Swift.Never?

protocol ViewModifier {
associatedtype Body: View
typealias Content = _ViewModifier_Content
func body(content: Self.Content) -> Self.Body
}
extension ViewModifier where Self.Body == Swift.Never {
public func body(content: Self.Content) -> Self.Body
}

struct _ViewModifier_Content where Modifier: ViewModifier {
typealias Body = Swift.Never
static func makeView(..) {...}
}

2 Likes
  1. Why do some SwitUI views have never as their body?

SwiftUI views have an infinite recursion problem. That is, if a view has a body that is a composition of other views, then where does it stop? A view contains views contains views contains....

SwiftUI however has a smart workaround for this: Mark the body as ā€œnever returnā€ when the view does not contain a body in a SwiftUI sense. These would be considered primitive SwiftUI types. When SwiftUI tries to decide what to present the user based on these types, it knows it can’t look at the body. It will never return one. For us as users, this doesn’t make much sense, because SwiftUI doesn’t know what we’re asking to show, but if they’re built-in SwiftUI types, the framework can special-case them, ignore the body, and do what it knows it should to show ā€œTextā€ for example.

  1. Is there a general rule for which has Never?

I believe the rule is simple: is the view a composite of other SwiftUI views, or is it a core SwiftUI type? If it’s a primitive type that SwiftUI uses underlying frameworks to present, then it will return never. Button however consists of the views that make up the button, eg text, image, so it makes sense to have a body - those subviews.

I’m personally unsure of the exact reasoning for 3, so I’ll leave it to others to explain.

5 Likes

I was wondering if someone can shed some light around this:
1- why some SwiftUI Views have body = Swift.Never.
2- is there a general rule for that? for example List().body = Swift.Never, while Button().body is not.
3- Also, by the same token, why in struct _ViewModifier_Content below, the struct needed to have body == Swift.Never?

Let's say you create a custom View:

struct MyView: View {
    var body: some View {
        Button(action: { }) {
            Text("Hello")
        }
    }
}

And at some point SwiftUI needs to draw a MyView on the screen. How does it know what to draw? It asks the MyView for its body, and gets some sort of Button. So now SwiftUI needs to draw the Button. So it asks the Button for its body and gets back some sort of View. And then it has to ask that button body for its body, and so on, ad infinitum, because every View has a body that is itself a View.

The way Swift solves this is quite clever. Each nested call to body takes half as long as the prior call, so if asking for MyView's body takes 1 microsecond, then asking for the Buttons body takes 1/2 of a microsecond, and asking for the Button's body's body takes 1/4 of a microsecond, and so on, and this is a geometric series whose sum is 2 microseconds, so it only takes Swift 2 microseconds to make the infinite number of body requests needed to draw MyView.

That last paragraph was just my little joke, ha ha. Ignore it. Here's the real answer.

Every View must have a body whose value is itself some sort of View, but SwiftUI can't really make an infinite number of calls to draw a view, so it has to cut the recursion short somehow. To end the recursion, SwiftUI has a variety of ā€œprimitiveā€ views that it can draw without asking for body. These include ā€œatomicā€ views like Text, Image, and Spacer that don't have subviews, but it also includes some compound views like List and VStack that do have subviews.

SwiftUI is never going to ask one of these primitive views for its body, and nobody else should ask for it either, because there is no good value to return. But the View protocol still requires each one to define a Body type and a body property.

The Swift standard library defines a good type to use for situations like this: Never. There are no values of the Never type. (If you want to sound like a type theorist, tell your friends it's ā€œuninhabitedā€.) If you see a function that takes a Never argument, you cannot call the function, and if you see a function or a property that returns Never, you know it cannot return at all. It will either run forever, or crash the program.

So first, SwiftUI makes Never conform to View, something like this:

extension Never: View {
    typealias Body = Never
    var body: Never { fatalError() }
}

And then, as you discovered, SwiftUI uses Never as the Body for its primitive views.

Since Button has a non-Never Body, we can deduce that it is probably not a primitive view. It might nevertheless have some special handling, but we can guess that SwiftUI probably does ask a Button for its body when it needs to draw the Button.

As for _ViewModifier_Content, this is also a type that conforms to View, but it must be a SwiftUI primitive. SwiftUI is never going to ask a _ViewModifier_Content for its body, and you shouldn't either, so its Body type is Never.

13 Likes

Moved to #swift-users as this is not a discussion about the general language evolution, but a framework from Apple.

thank you so much. You answer has helped clarify the story behind the how SwiftUI is designed. So the bottom line body = Never is for the swiftUI compiler to determined how to process a View (primitive vs not). Many thanks

1 Like

Many thanks Rod. between your answer and Mayoff, I think the picture is clearer. Cheers

With all this in mind, does anyone know (or can speculate) why AnyView has Body = Never? AnyView doesn't know until runtime what kind of view it's going to be rendering, either native or composite?

I’d speculate that AnyView will provide view information via other (internal) channel. Since body must have a type, having it again be AnyView wouldn’t work. Returning AnySubview will much get us back to where we started. Likely it’d directly be using the layout mechanism underneath.

Well we canā€˜t answer that question unless someone from the SwiftUI team jumps in. One definitely right answer is that not every view is a 'view' by definition and not every view renders. Other than that, itā€˜s an implementation detail of the framework to switch the way it processes the behavior defined by the type.

But you cannot simple write the same code, it won't work :)

Code below get from SwiftUI with rename Types :slight_smile:

public protocol MyView {
  associatedtype Body: MyView = Never
  var body: Body { get }
}

private extension MyView where Body == Never {
  var body: Body { fatalError() }
}

extension Never: MyView { }

Or more appropriate

public protocol MyView {
  associatedtype Body: MyView
  var body: Body { get }
}

private protocol BasicView: MyView { }

extension BasicView {
  var body: Never { fatalError() }
}

extension Never: BasicView {}
1 Like

(post deleted by author)