Tom Lieber's Microblog

How and why to you might need to use AnyView in SwiftUI

AnyView is my biggest pet peeve in SwiftUI because:

Let’s say you’re pulling horizontalSizeClass from your @Environment because there’s a UI element that won’t fit in a compact view. So you change:

var fooView: some View {
  return Text("foo")
}

to:

var fooView: some View {
    if horizontalSizeClass == .compact {
        return EmptyView()
    } else {
        return Text("foo")
    }
}

Inexplicably, you get a compiler error: “Function declares an opaque return type, but the return statements in its body do not have matching underlying types.”

It’s worse if the condition is inside another block, like a GeometryReader:

var fooView: some View {
    GeometryReader { geometry in
        if horizontalSizeClass == .compact {
            return EmptyView()
        } else {
            return Text("foo")
        }
    }
}

Then you get “Generic parameter ‘Content’ could not be inferred” with a series of “Fix” buttons that just make the problem worse.

The root issue is that View has a type parameter (it’s why fooView’s type is “some View”) that EmptyView and Text set to different values, and the compiler is unwilling to automatically pick a setting of that parameter that is compatible with both.

The fix is to wrap each returned view with AnyView, which sets the parameter to Never:

var fooView: some View {
    if horizontalSizeClass == .compact {
        return AnyView(EmptyView())
    } else {
        return AnyView(Text("foo"))
    }
}