Say No to AnyView in SwiftUI iOS Applications

SwiftUI allows developers to use heterogenous view types by making use of AnyView type. AnyView encloses any kind of SwiftUI type into a generic type that can be returned from a function. In this article, we will take a look at,

  1. Why developers may want to use AnyView type in the application
  2. What are the downsides of using it
  3. How can you refactor your app to not use AnyView type

Why developers may want to use AnyView in the application?

AnyView comes into the picture when you are writing a function that returns heterogenous view types. In that case, you can set your function's return type as generic some View and cast view to AnyView before returning it. Let's understand it with an example,


struct CarnivoreView: View {
    var body: some View {
        Text("Carnivore")
    }
}

struct FishView: View {
    var body: some View {
        Text("Fish")
    }
}

struct BirdView: View {
    var body: some View {
        Text("Bird")
    }
}

enum Animal {
    case carnivore
    case fish
    case bird
}

.....
...

func topView(for animal: Animal) -> some View {
    switch animal {
    case .carnivore:
        return AnyView(CarnivoreView())
    case .fish:
        return AnyView(FishView())
    case .bird:
        return AnyView(BirdView())
    }
}

In the above example, the function topView returns the view type depending on the type of animal passed to it. Since it could either be CarnivoreView, FishView or BirdView, we are using some View as a return type and casting them to AnyView before returning it.

Now that we know why and where AnyView might get used, let's try to understand some downsides of using it.

What are the downsides of using it?

AnyView is a type-erasing wrapper type. Using AnyView hides the if-else structure of code and the underlying concrete type used for building a view. When the compiler looks at the returned type, all it sees is a AnyView type. This not only makes code hard to read for other developers but can also make it difficult to observe and analyze view structure during debugging.

For example, when the compiler emits useful compile-time diagnostics, using AnyView makes it hard to understand what's going on under the hood since all it exposes is an AnyView during the debugging session.

some View = AnyView

Another downside of using AnyView is, it also results in poor app performance since SwiftUI's view-updating framework cannot really determine which underlying view has changed due to type-erasing AnyView usage. If there is really a need for this use case, please use the generic types to preserve the static type instead of passing AnyView around.

How can you refactor your app to avoid AnyView type?

Fortunately, it's possible to avoid AnyType and also to use different view types using a ViewBuilder construct. ViewBuilder is an annotation that can be applied to view building functions that can return any type of view without casting it to AnyView before returning. The return type is still going to be some View, but it helps preserve underlying type information and the compiler can analyze the internal view structure without losing debugging information.

To apply ViewBuilder annotation, simply prefix function with @ViewBuilder annotation and remove all the AnyView casts inside topView function.


@ViewBuilder func topView(for animal: Animal) -> some View {
    switch animal {
    case .carnivore:
        CarnivoreView()
    case .fish:
        FishView()
    case .bird:
        BirdView()
    }
}

When using ViewBuilder, it is also not necessary to specify return keyword for returning the view, so we've ommitted it

Now if you analyze the view structure returned by topView, it will look something like this,


some View = _ConditionalContent<
				_ConditionalContent<CarnivoreView, FishView>, 
				BirdView>

It allows you to inspect what lies inside the view returned by the function and how the choice of final view is evaluated.

Summary

So that's all I wanted to talk about why not to use AnyView and how to build views using ViewBuilder in SwiftUI applications. ViewBuilder offers an excellent way to build reusable views, preserve their internal structure while debugging, and also to improve the app performance by helping update only those underlying views whose data might have changed.

Hopefully, this blog post was helpful for you to understand how to build SwiftUI apps using ViewBuilder and build performant iOS apps. If you have any other questions, comments, or feedback, please feel free to reach out on LinkedIn.

Support and Feedback

If you like my blog content and wish to keep me going, please consider donating on Buy Me a Coffee or Patreon. Help, in any form or amount, is highly appreciated and it's a big motivation to keep me writing more articles like this.

Consulting Services

I also provide a few consulting services on Topmate.io, and you can reach out to me there too. These services include,

  1. Let's Connect
  2. Resume Review
  3. 1:1 Mentorship
  4. Interview Preparation & Tips
  5. Conference Speaking
  6. Take-home Exercise Help (iOS)
  7. Career Guidance
  8. Mock Interview