Vlad Poncea
Vlad Poncea

Reputation: 359

How can I add a View as a struct variable?

I am looping through an array of Models and I want a different navigation destination for each one. What is the best approach to that? Here is the model

struct HomePageGridItem: Identifiable {
    var id: Int
    var image: String
    var title: String
    var desc: String
}

And here is what I get when I try to add a destination error

I don't know what I'm missing here.

Upvotes: 0

Views: 1166

Answers (1)

Carter Foughty
Carter Foughty

Reputation: 298

I'd agree that you shouldn't do this - the view should handle routing, whereas the model should inform routing.

However, for your learning, it may be useful to understand a potential solution and what the error you're getting means - it comes up a lot in SwiftUI development.

Protocol 'View' can only be used as a generic constraint because it has Self or associated type requirements

This error is displayed when the protocol in question (View in this case), has an associated type defined internally, and you have not set a requirement for what this associated type should be. An example of a protocol with an associated type might be the Identifiable protocol...

protocol Identifiable {
    associatedtype ID
    var id: ID { get set }
}

As you can see, there is an associated type defined - ID. This is a generic, meaning it can take on any form as needed for this protocol's use. In each use of the protocol, the associatedtype (or generic) can only be defined upon initialization of the conforming object OR in your case, the declaration of a variable. An example implementation of Identifiable might assign ID as type String. In that case, the id variable would be of type String.

As stated, the protocol in your situation is View. It's definition looks something like this...

protocol View {
    associatedtype Body
    var body: Body
}

The generic in this case is Body, which must be defined upon definition of the View. Read more about protocols with associated types and their uses here:

https://docs.swift.org/swift-book/LanguageGuide/Generics.html#ID189

In your case, you must define your property destination as a concrete implementation of protocol View, because the associated type must be static for the definition of your variable. One useful concrete implementation of View is AnyView. Your model would look like this...

struct HomePageGridItem: Identifiable {
    var id: Int
    var image: String
    var title: String
    var desc: String
    var destination: AnyView
}

To cast 'any view' as an AnyView, simply do this...

AnyView(Color.red)

Now, rather than the view being of type Color, it will be of type AnyView. If you want to use your model, all you would have to do is wrap your desired view in an instance of AnyView when assigning it to the HomePageGridItem.destination variable.

Upvotes: 1

Related Questions