Swift UI and choice in a NavigationView

I'm discovering SwiftUI, thinking that it is the future for developping Applications.

the first thing (I'm sure it is very simple) I have difficulties is making a choice in a dynamic List.


In a classic Swift I make it like this

In my menuViewController, I have these declarations:

private var choix = ["Adjectifs", "Adverbes", "Noms", "Verbes", "Prépositions", "Expressions", "Phrases", "Racines", "Quizz"]//,  "test"]
private var actions = [adjectifsViewController.self, adverbesViewController.self, nomsViewController.self, verbesViewController.self, prepositionsViewController.self, expressionsViewController.self, phrasesViewController.self, associationsViewController.self, listerQuizzViewController.self] //, menu1ViewController.self]


I draw a UITableView with choices ad when I click on a row of my tableView:


func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        if actions[indexPath.row] != "" {
            let aClass = actions[indexPath.row]
            let controller = aClass.loadFromNib()
            self.show(controller, sender: self)
        }
    }


Now of course I want to write this in SwiftUI


first I have a struct like this:

struct IvritMenu: Identifiable {
    let id: Int
    let text: String
    let lien: click
}

enum click: Hashable {
        case adjectifs
        case adverbes
        case noms
        case verbes
}


then in the View, I write the variable:

var menu = [
        IvritMenu(id: 0, text: "Adjectifs", lien: .adjectifs),
        IvritMenu(id: 1, text: "Adverbes", lien: .adverbes),
        IvritMenu(id:2, text: "Noms", lien: .noms),
        IvritMenu(id:3, text: "Verbes", lien: .verbes)]


and Finally:

var body: some View {

        NavigationView {
        List(menu)  { choix in
                ListeChoix(choix: choix)
            }
            .navigationBarTitle(Text("Ivrit"))
        }
    }


now the difficult part (for me) is to write ListeChoix


struct ListeChoix: View {
    var choix: IvritMenu
    var body: some View {
        switch choix.lien {
        case .adjectifs:
            return Adjectifs()
        defaul make itt:
            return Adverbes()
        }
    }
}


this generate an error Function declares an opaque return type, but the return statements in its body do not have matching underlying types


I think this error is caused by the return which returns different types of View, but I don't know how to make it

Answered by Claude31 in 399878022

The change

struct IvritMenu2: Identifiable { 
    let id: Int 
    let text: String 
    let destination: AnyView 
}

Seems to work properly.


I am not sure of the answer to your question.

does it means that the view Adjectifs and Adverbes are always created,

But, I think that they are created when you navigate the link.


If OK, don't forget to close the thread.

Problem is that you need to return a View.

Read this:

h ttps://www.hackingwithswift.com/quick-start/swiftui/how-to-return-different-view-types

What is the type of Adjectifs() ?

May read this as well:

https://stackoverflow.com/questions/56506057/function-declares-an-opaque-return-type-error-when-declaring-a-view-as-a


I did the following (In playground with OSX Mojave) to show the pattern on how to return a value.


class IvritMenu: ObservableObject {
    @Published var id = 0
    @Published var text = "0"
}
struct ContentView: View
{
  let data = [
    "Test 1","Test 2","Test 3"
  ]
   
    @ObservedObject var selection : IvritMenu
  
  var body: some View
  {
    List
    {
      ForEach(data, id:\.self)
      {
        item in
        Text(item)
            .onTapGesture {
                switch item {
                case "Test 1":
                    self.selection.id = 1
                    print("1")
                case "Test 2":
                    self.selection.id = 2
                    print("2")
                case "Test 3":
                    self.selection.id = 3
                    print("3")

                default: self.selection.id = 0
                }
           }

        }
    }
  }
}


It works, just get an error message,

=== AttributeGraph: cycle detected through attribute 38 ===

due to a problem in SwiftUI with Lists

Just had to ignore it

https://stackoverflow.com/questions/58147103/attributegraph-cycle-detected-through-attribute-using-state-in-playgrounds

I'm not sure I understand your answer


I have this structure:

struct IvritMenu: Identifiable {
    let id: Int
    let text: String
    let destination: some View
}


On line 4 Xcode whow an error: Property declares an opaque return type, but has no initializer expression from which to infer an underlying type


Is it impossible to declare a variable as a view?

Yes you can, but not some View:


struct IvritMenu2: Identifiable {
    let id: Int
    let text: String
    let destination: AnyView
}

So if I have this code;


import SwiftUI


struct IvritMenu: Identifiable {
    let id: Int
    let text: String
    var destination: AnyView
}

struct MenuGeneral: View {
    var menu = [
        IvritMenu(id:1, text: "Adjectifs", destination: AnyView(Adjectifs())),
        IvritMenu(id:2, text: "Adverbes", destination: AnyView(Adverbes()))
    ]
    var body: some View {
       
        NavigationView {
            List(menu) { choix in
                NavigationLink(destination: choix.destination) {
                    Text(choix.text)
                }
            }
            .navigationBarTitle("Ivrit")
        }
    }
}



struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        MenuGeneral()
    }
}


converning lines 9 and 10 does it means that the view Adjectifs and Adverbes are always created, or are they created only when I click on one of the links?

Accepted Answer

The change

struct IvritMenu2: Identifiable { 
    let id: Int 
    let text: String 
    let destination: AnyView 
}

Seems to work properly.


I am not sure of the answer to your question.

does it means that the view Adjectifs and Adverbes are always created,

But, I think that they are created when you navigate the link.


If OK, don't forget to close the thread.

Swift UI and choice in a NavigationView
 
 
Q