3
votes

I have defined a few (up to many) different SwiftUI Views:

ViewA(), ViewB(), ViewC() .. ViewN()

Each View contains a specific information that I want to present depending on the choice made by the user..

I created a Hashable, Identifiable list of items and I want to link each item to one specific view. But I can not seem to overcome the errors..

Here is a specific example of exactly what I am trying to do:

//Country Definitions:

import Foundation
import Combine
import SwiftUI

let Countries = [
    CountryModel(countryID: "US", countryName: "United States", countryView: USAView() )
    CountryModel(countryID: "UK", countryName: "United Kingdom", countryView: UKView() )
]

struct CountryModel: Identifiable, Hashable {
    
    let id:UUID
    let countryID:String
    let countryName:String
    let countryView:View   //I have tried AnyView here, different issues, still no go...
    
    init(countryID:String, countryName:String, countryView:View) {
        self.id = UUID();
        self.countryID = countryID
        self.countryName = countryName
        self.countryView = countryView
    }
}

How it is planned to be used in theory is in a NavigationView / NavigationLink as such:


struct ContentView: View {
    
    var body: some View {
        
        NavigationView {
            
            ForEach(Countries) { thisCoutry in
                
                NavigationLink(destination: thisCoutry.countryView) { //Also tried forcing as! View, no good
                    MyItemCell(itemName: thisCoutry.countryName, itemDesc: thisCoutry.countryID)
                    
                }
            }
        }
    }
}

(MyItemCell is just a View to format the name and ID of the item)..

Thus far, trying to use "View", I get the errors:

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

and something about not conforming to Equatable. When I add Equatable and have it add the stub with return true, no help...

struct CountryModel: Hashable, Identifiable, Equatable {
    static func == (lhs: CountryModel, rhs: CountryModel) -> Bool {
        return true
    }

I also get an error proclaiming that this does not conform to Hashable, so I tried taking that out and still no go..

Any ideas greatly appreciated. Trying to avoid a long list of Nav Links as SwiftUI seems to get funky at/around/after 10 or so and I have to start Grouping, or being otherwise more creative...

struct ContentView: View {
    
    var body: some View {
        
        VStack{
            NavigationView {
                
                NavigationLink(destination: ViewA()) {
                    MyItemCell(itemName: "United States", itemDesc: "USA")
                    
                }
                
                NavigationLink(destination: ViewB()) {
                    MyItemCell(itemName: "United Kingdom", itemDesc: "UK")
                    
                }
            }
        }
    }
}
1

1 Answers

1
votes

You can go with AnyView type erasure wrapper (but it should be not only declared in model but used explicitly when created - casting does not work here, this I assume was the origin of errors):

let Countries = [
    CountryModel(countryID: "US", countryName: "United States", 
       countryView: AnyView(USAView()) )    // << here !!
    CountryModel(countryID: "UK", countryName: "United Kingdom", 
       countryView: AnyView(UKView()) )
]

struct CountryModel: Identifiable, Hashable {
    
    let id:UUID
    let countryID:String
    let countryName:String
    let countryView:AnyView
    
    init(countryID:String, countryName:String, countryView:View) {
        self.id = UUID();
        self.countryID = countryID
        self.countryName = countryName
        self.countryView = countryView
    }
}