0

So I am trying to create a router. I intended to route directly to a view in the body such as..

struct MyView: View {
  let page: Page
   var body: some View {
     router(page: page)
    }
 }

In the body I tried to declare a function...

func router(page: Page) -> View 

which gave me the error:

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

so I then made it

func router<T: View>(page: Page) -> T 

then in the body I used a switch statement:

 func router<T: View>(page: Page) -> T {

switch page {
  case .page1: 
     return Page1()
        ....

 }
}

then Xcode recommended that I cast all returned views as! T

which ultimately led me to the generic warning against generics as been below:

Text

I search SO for this problem and there are many variants but none led to me understand why this doesn't work.

Sergio Bost
  • 2,591
  • 2
  • 11
  • 29
  • 2
    Does this answer your question? [How to pass one SwiftUI View as a variable to another View struct](https://stackoverflow.com/questions/56938805/how-to-pass-one-swiftui-view-as-a-variable-to-another-view-struct) – lorem ipsum Jan 28 '21 at 02:03
  • 1
    @loremipsum It looks like it might but its a deep dive and I am literally burnt out for the night, thanks for the reference, will read when I can come to my senses. – Sergio Bost Jan 28 '21 at 02:06

1 Answers1

1

In this case, you're overcomplicating things a bit. Your router function can just return some View like your other body functions can:

enum AirFormulas {
    case formula1
    case formula2
}

struct RouterView : View {
    let formula : AirFormulas
    var body: some View {
        router(formula: formula)
    }
}

@ViewBuilder func router(formula: AirFormulas) -> some View {
    switch formula {
    case .formula1:
        Text("Hi")
    case .formula2:
        Image(systemName: "plus")
    }
}

Note a couple of things:

  1. I used @ViewBuilder so that I could return a variety of View types from the function. It also means I'm not going to explicitly call return. More reading: https://swiftwithmajid.com/2019/12/18/the-power-of-viewbuilder-in-swiftui/

  2. Another (uglier) way to do this is to wrap all of the returned values with AnyView and return AnyView instead of some View

Finally, why you were getting the error: In the case of your original code, T couldn't be inferred because there was nothing to infer it from. You pass an AirFormulas, which has no information about T. And the return value can be a variety of View types, but that's what we use some View to achieve.

jnpdx
  • 45,847
  • 6
  • 64
  • 94
  • Thanks, that led to quick understanding and gave me food for thought for the future on understanding more about ViewBuilders – Sergio Bost Jan 28 '21 at 02:21