SwiftUI @ViewBuilder Result is a TupleView, How is Apple Using It And Able to Avoid Turning Things Into AnyVIew?

I know this thread is a little old, but I found something really interesting looking through SwiftUI’s interface file.

AnyView provides a public initializer:

public struct AnyView: View {
  // ...

  public init?(_fromValue value: Any)
}

This means that SwiftUI can do something like the following in TupleView:

extension TupleView {
  /// Force-opens the given box.
  internal func open(_ box: Any) -> AnyView {
    guard let view = AnyView(_fromValue: box) else {
      fatalError("TupleView contains non-view elements") 
    }

    return view
  }

  internal var children: [AnyView] {
    switch value {
    case let tuple as? (Any, Any): return [open(tuple.0), open(tuple.1)]
    // Larger-tuple dynamic casts...
    default: return [open(value)]
    }
  }
}

Then, to access views' elements, the _VariadicView APIs can be used. You, first, need to provide a root type conforming to a certain ...Root protocol:

struct Root: _VariadicView.UnaryViewRoot {
  func body(children: _VariadicView.Children) -> some View {
    // Children is a random-access collection; here we just dump its child.
    children.forEach { dump($0) }

    return EmptyView()
  }
}

The root type is used to layout elements that are passed to it by the _VariadicView.Tree:

struct Container<Content: View>: View {
  private let tree: _VariadicView.Tree<Root, Content>

  init(@ViewBuilder _ content: () -> Content) {
    tree = _VariadicView.Tree(Root(), content: content)
  }

  var body: some View { tree }
}

VStack seems to be implemented this way. However, this approach is still quite limited by the lack of access to internal view-outputs APIs. As a result, you will only be able to use built-in containers and modifiers. Using these APIs also resulted in a lot of crashes in my test playground, so this is more of an educational post about the inner workings of SwiftUI.

8 Likes