Why SwiftUI primitives have body type Never?

When defining a SwiftUI view, it comes automatically to write struct MyView: View followed by var body: some View { ... }. All our views are composed of other views. At some point SwiftUI needs to draw something on the screen:
when does it end? How does SwiftUI know that it has reached the bottom of a view hierarchy?

In this article, let's continue our exploration of SwiftUI's inner workings.

The View protocol

Every SwiftUI view is a type conforming to the View protocol:

public protocol View {
  associatedtype Body: View
  @ViewBuilder var body: Self.Body { get }
}

Since this is a Swift protocol, we can make any type conform to it, for example, String:

extension String: View {
  public var body: some View {
    Text(self)
  }
}

this is just an example, not a suggestion nor a best practice.

Which allows us to write a String directly into a View declaration:

struct ContentView: View {
  var body: some View {
    "Hello world!"
  }
}

As we're using the Text primitive in String's body, this will work as expected, but what if we didn't? Let's build a new SwiftUI view which uses none of SwiftUI's primitives:

struct MyView: View {
  var body: some View {
    self
  }
}

In this case we're defining a new View called MyView, here we use it in ContentView:

struct ContentView: View {
  var body: some View {
    MyView()
  }
}

This builds fine. However, as MyView's' body is the view itself, we're stuck on an infinite recursion, which will make SwiftUI terminate our app.

Despite the View protocol letting us conform pretty much anything to it, if we want to use those declarations in SwiftUI, we must use SwiftUI primitives or be ready to see our app crash.

What do these SwiftUI primitives have that make them unique, allowing SwiftUI to break the infinite recursion we've found ourselves in? The answer is in their body type: Never.

Never

Swift 3.0 has brought us Never, an uninhabited type: Never is a type with no possible values, making it impossible for us to get or create an instance.

We might have met Never for example:

Let's declare a view with body type Never:

struct ImpossibleView: View {
  var body: Never
}

This builds! However, we cannot use it: we can't instantiate it without passing something like fatalError(). Regardless, let's implement the body and run our app:

struct ImpossibleView: View {
  var body: Never {
    fatalError("This will make our app 💥")
  }
}

Here's our ContentView:

struct ContentView: View {
  var body: some View {
    ImpossibleView()
  }
}

Unsurprisingly, our app will crash once again, However, the crash reason is Fatal error: ImpossibleView may not have Body == Never: file SwiftUI, line 0, not our This will make our app 💥.

Reading throughout the stack trace, we will see an assertionFailure within an internal SwiftUI's BodyAccessor.makeBody(container:inputs:fields:) method, which is not happy with our ImpossibleView body type.

This is the same method that will crash our app if we pass a class instance instead of a value type.

Only views declared within SwiftUI are allowed to have body type Never. Despite not having access to BodyAccessor's code, it's clear that those views would either pass this assertion or that they'd take a different, special path.

SwiftUI can't keep asking for view bodies forever: it needs a special set of views, a.k.a. a set of primitives, that it can draw without asking for their body. This is why Text, ZStack, Color, etc., have Never as their body type.

Is Never a View?

A type conforming to View needs to return a body that is also a View: Never is a view.

SwiftUI knows not to ask for the body of views with body type Never, either by crashing if it's not a primitive or doing something else otherwise. However, since we must make our code compile, SwiftUI needs to extend Never to be a View: the ultimate, impossible view.

To confirm this, we can inspect SwiftUI's headers, where we will find the following declaration (spread in a few places):

extension Never: View {
  public typealias Body = Never
  public var body: Never { get }
}

The SwiftUI team could have declared another special type to be used instead of Never. However, I find this solution very elegant and perfectly fitting for the use case.

Conclusions

In this article, we've explored how SwiftUI breaks the infinite recursion challenge when drawing views and how it uses the special Swift's type Never to achieve that elegantly.

I hope you've found this article helpful: please let me know if I've missed anything!

Thank you for reading, and stay tuned for more SwiftUI articles!

Bonus track

Since the article is about impossible views, just for fun, I want to share another completely legit and 100% crashing way to "build" views: declare nothing but any modifier.

struct ContentView: View {
  var body: some View {
    border(Color.black)
  }
}

// or

struct ContentView: View {
  var body: some View {
    padding()
  }
}

// or

struct ContentView: View {
  var body: some View {
    ignoresSafeArea()
  }
}

// etc

So many possibilities! 💣

Are you aware of any other interesting ways to crash SwiftUI? I'd love to know!

â­‘â­‘â­‘â­‘â­‘

Further Reading

Explore SwiftUI

Browse all