Storing SwiftUI Views in property

I am interested in storing one of several SwiftUI views as a destination for a dynamically generated button. Programmatically, I create a struct to store the modules to be created:


struct Module: Identifiable {
    var id: Int
    var name: String
    var destinationView = NewsView() // var destinationView: View - - - does not work
   
}


An array exists which stores the modules to be created on the home page view:


ForEach(sessionParts[currentSessionPart].modules) { module in
                   
  Group {
       NavigationLink(destination:
                           
       module.destinationView
                           
  ) {
       ZStack {
            HomeScreenNav() // View defining button
                               
            Text("\(module.name)")
            .font(.largeTitle)
            .color(Color.black)
            }
       }
   }
}


This works correctly and a button is created that links to the NewsView view. But if I try to define the variable by type View, it does not work. Nor can I overwrite the variable with a different View.


I have stretched my limited Swift skills and tried a few things, but have been unable to get closer to a solution. Thanks for any help.

Answered by mayoff in 370641022

You cannot declare a property of type View because View is a protocol with an associated type. Instead, you need to declare destinationView to be of a type that conforms to the View protocol. Sometimes this is hard, because views often have complicated types like VStack<TupleView<(Text, Text)>> (and that's not even a particularly complicated example).


In your case, it's easy, because you have created a separate NewsView type that conforms to View. So you can just say this:


var destinationView: NewsView = NewsView()


However, this means that destinationView can only hold a value of type NewsView. If you want to change it to an OldsView when the user clicks a button, you can't, because destinationView cannot hold an OldsView.


If you want destinationView to be able to hold any value whose type conforms to View, you need to use the type-erasing wrapper AnyView. If you have any value whose type conforms to View, you can wrap it in an AnyView to hide the specific type:


var destinationView: AnyView = AnyView(NewsView())


Then you can later assign some other view to it:


func buttonWasTapped() {
    destinationView = AnyView(OldsView())
}
Accepted Answer

You cannot declare a property of type View because View is a protocol with an associated type. Instead, you need to declare destinationView to be of a type that conforms to the View protocol. Sometimes this is hard, because views often have complicated types like VStack<TupleView<(Text, Text)>> (and that's not even a particularly complicated example).


In your case, it's easy, because you have created a separate NewsView type that conforms to View. So you can just say this:


var destinationView: NewsView = NewsView()


However, this means that destinationView can only hold a value of type NewsView. If you want to change it to an OldsView when the user clicks a button, you can't, because destinationView cannot hold an OldsView.


If you want destinationView to be able to hold any value whose type conforms to View, you need to use the type-erasing wrapper AnyView. If you have any value whose type conforms to View, you can wrap it in an AnyView to hide the specific type:


var destinationView: AnyView = AnyView(NewsView())


Then you can later assign some other view to it:


func buttonWasTapped() {
    destinationView = AnyView(OldsView())
}

Thank you! This was what I needed. I tried anyview, but had the syntax wrong. It is now working for me.

Storing SwiftUI Views in property
 
 
Q