AnyView performance

Hello everyone!
I read that AnyView can impact app performance in a negative way because per Apple's documentation:
Whenever the type of view used with an AnyView changes, the old hierarchy is destroyed and a new hierarchy is created for the new type.

struct MyView: View {
  @State flag: Bool
  
   var body: some View {
      AnyView(
          flag ? Text("Text") : Button("Button")
      )
   }
}

So when the flag is toggled, the type of the view changes, so the new hierarchy is created. That makes sense to me.

But if I write the code this way.

struct MyView: View {
  @State flag: Bool
  
   var body: some View {
       flag ? AnyView(Text("Text")) : AnyView(Button("Button"))
   }
}

Technically, the type of the view wrapped by AnyView doesn't change when the flag is toggled. Would that still cause the whole view hierarchy to be created and redrawn?

1 Like

Your first example has a few syntax errors. Here's a corrected version:

struct MyView: View {
  @State var flag: Bool

   var body: some View {
      AnyView(
          flag ? Text("Text") : Button("Button") { }
      )
   }
}

However, it still doesn't compile. The error is

Result values in '? :' expression have mismatching types 'Text' and 'Button<Text>'

Your second example has the same syntax errors. Here's a corrected version:

struct MyView: View {
  @State var flag: Bool

   var body: some View {
       flag ? AnyView(Text("Text")) : AnyView(Button("Button") { })
   }
}

This version does compile.

You said

Technically, the type of the view wrapped by AnyView doesn't change when the flag is toggled.

But that is not true. The type of view wrapped my AnyView is Text when flag is true, and Button<Text> when flag is false. So whet flag changes from true to false, SwiftUI presumably has to discard the backing structures of Text, and create backing structures for Button<Text>.

However, although I've also heard the Apple advice about avoiding it, all the anecdotal third-party reports I've heard say that the overhead of AnyView is not normally significant.

Consider this view:

struct MyAdviceFollowingView: View {
    @State var flag: Bool

    var body: some View {
        if flag {
            Text("Text")
        } else {
            Button("Button") { }
        }
    }
}

This view's body returns a value of type _ConditionalContent<Text, Button<Text>>. This type tells SwiftUI that the only possible backing structures it might need here are for Text and for Button<Text>. Maybe this lets it be more efficient about memory allocation for the appropriate structures. But when flag changes from true to false, SwiftUI still has to at least set up the backing structures for Button<Text>; that work is unavoidable. Probably it also discards the structures it had for Text; otherwise, it's still using memory (and maybe window server resources?) to keep them around when they might never be needed again.

1 Like

Thank you for correcting the syntax errors. I might have interpreted their documentation wrong. That makes sense now.

Yeah I'd love to avoid AnyView since I am not sure how much of the performance impact would be but in my use case, there is no better option.
Because some View can't be used as a return type in protocol, I need something I can use, and AnyView is the only option :confused:

Are you saying you have a protocol that refines View? That wasn’t part of your sample.

I'm skeptical of this. Could you post your use case?

This is a little vague. Can you please expand on this?