SwiftUI NavigationLink destination

In truth, I do not fully understand JSON Files and I am new to Swift. I am trying to be a bit too clever and build my menu from a JSON file.

[
    {
        "description": "Readings Entry",
        "target": "ReadingsEntry",
        "icon": "barometer",
    },
    {
        "description": "Readings Entry",
        "target": "ReadingsView()",
        "icon": "tablecells.badge.ellipsis",
    },
    {
        "description": "Food Diary",
        "target": "FoodDiary()",
        "icon": "fork.knife.circle",
    },
    {
        "description": "Readings Entry",
        "target": "Settings()",
        "icon": "gearshape",
    }
]

Because I don't know any better I have stored the destination view (target) as a String in the "struct" that I have constructed to import the JSON data.

import SwiftUI

struct dcMenu: Codable, Identifiable {
    enum CodingKeys: CodingKey {
        case description
        case target
        case icon
    }
    var id = UUID()
    var description: String
    var target: String
    var icon: String
}

class ReadData: ObservableObject {
    @Published var lineText = [dcMenu]()
    
    init(){
        loadData()
    }
    
    func loadData() {
        guard let url = Bundle.main.url(forResource: "menu", withExtension: "json")
        else {
            print("Json file not found")
            return
        }
        
        let data = try? Data(contentsOf: url)
        let lineText = try? JSONDecoder().decode([dcMenu].self, from: data!)
        self.lineText = lineText!
    }
}

But the issue this leaves me with is when I come to construct the actual menu, How do I use the string "target" as the "destination" of the navigation link?

struct ContentView: View {
    @ObservedObject var menuLines = ReadData()
    
    var body: some View {
        NavigationSplitView {
                        .
                        .
                        .
                List(menuLines.lineText) { lines in
                    NavigationLink(destination: lines.target){
                        Image(systemName: lines.icon)
                        Text(lines.description)
                    }
                }

                       .
                       .
                      . 
                .navigationSplitViewColumnWidth(min: 75, ideal: 100)
        } detail: {
                     .
                     .
                     .
         }
        .navigationTitle("Diabetes Control")
    }
}
Answered by DTS Engineer in 790178022

@jamesm46 Use the navigationDestination(for:destination:) modifier to associates the destination view with the presented data type. For example:


struct ContentView: View {
    var body: some View {
        NavigationSplitView {
            List {
                NavigationLink(destination: Color.mint) {
                    Text("Mint")
                }
                
                NavigationLink(destination: Color.pink) {
                    Text("Pink")
                }
                
                NavigationLink(destination: Color.teal) {
                    Text("Teal")
                }
            }
            .navigationDestination(for: Color.self) { color in
                ColorDetail(color: color)
            }
        } detail: {
            Text("Select a color")
        }
    }
}

struct ColorDetail: View {
    var color: Color
    
    var body: some View {
        color.ignoresSafeArea()
    }
}

This just seems like a bad approach. You're running into difficulties because that's not how it's supposed to be done. Look up the localization videos and documentation if you want to localize strings and images. Use conditional viewbuilders if you want to swap views based on locale. If you're not doing this for localization, I'd assume you're trying to fetch additional functionality dynamically from a server--that's disallowed.

Also, turning everything into JSON means you lose things like code completion and compilation checks.

@jamesm46 Use the navigationDestination(for:destination:) modifier to associates the destination view with the presented data type. For example:


struct ContentView: View {
    var body: some View {
        NavigationSplitView {
            List {
                NavigationLink(destination: Color.mint) {
                    Text("Mint")
                }
                
                NavigationLink(destination: Color.pink) {
                    Text("Pink")
                }
                
                NavigationLink(destination: Color.teal) {
                    Text("Teal")
                }
            }
            .navigationDestination(for: Color.self) { color in
                ColorDetail(color: color)
            }
        } detail: {
            Text("Select a color")
        }
    }
}

struct ColorDetail: View {
    var color: Color
    
    var body: some View {
        color.ignoresSafeArea()
    }
}
SwiftUI NavigationLink destination
 
 
Q