ios – What is the professional way of using navigationDestination in a SwiftUI app that has multiple tabs and complex navigation?


I want to build an application that has different tabs and each tab has access to multiple views. Currently, this is how I handle it. I have created a singleton class that has all the information for routing in it. and since each route can have its own specific enums added to its array, I can limit access on different routes. and it gives me flexibility in performing certain actions.

final class AppData: ObservableObject {
    static var shared = AppData()
    
    // Active Tab
    @Published var activeTab: Tab = .home
    
    // Map Tab
    @Published var mapNavStack: [MapStack] = []
    
    // Leaderboard Tab
    @Published var leaderboardNavStack: [LeaderboardStack] = []
    
    // Home Tab
    @Published var homeNavStack: [HomeStack] = []
    @Published var homeActiveTab: HomeTab = .forYou
    
    // My Profile Tab
    @Published var myProfileNavStack: [MyProfileStack] = []
    @Published var myProfileActiveTab: MyProfileActiveTab = .stats
    @Published var showEditProfile: Bool = false
    
    // Authentication Tab (Only before sign-in)
    @Published var authNavStack: [AuthStack] = []
    
    func reset() {
        self.activeTab = .home
        
        self.homeNavStack.removeAll()
        self.mapNavStack.removeAll()
        self.leaderboardNavStack.removeAll()
        self.authNavStack.removeAll()
        
        self.myProfileNavStack.removeAll()
        self.myProfileActiveTab = .stats
        self.showEditProfile = false
    }
}

For example, LeaderboardStack enum looks like this:

enum LeaderboardStack: Hashable {
    case userProfile(id: String)
    case userConnections(userId: String, initTab: UserConnectionsTab)

    func hash(into hasher: inout Hasher) {
        switch self {
        case .userProfile(let id):
            hasher.combine("userProfile")
            hasher.combine(id)
        case .userConnections(let userId, let tab):
            hasher.combine("userConnections")
            hasher.combine(userId)
            hasher.combine(tab)
        }
    }
}

So leaderboard screen can only navigate to userProfile and userConnections.
And finally to make this all work I’m using this view modifier on LeaderboardView (Where I have Leaderboards’ NavigationStack)

.navigationDestination(for: LeaderboardStack.self) { link in
    switch link {
    case .userProfile(let id):
        UserProfileView(id: id)
    case .userConnections(let userId, let initTab):
        UserConnectionsView(userId: userId, activeTab: initTab)
    }
}

But the problem is if there is a common screen that every tab can access I need to duplicate the code. But the bigger problem is when I want to navigate using NavigationLink(value:label:), Since I don’t know which tab it’s going to be in I can’t use it. for example, I can’t hardcode LeaderboardStack.userProfile(id: "THEID") because it might be in the Home Tab so I’m being forced to append directly to the stack arrays based on the activeTab value.
I’m very new to Swift and SwiftUI. any help is much appreciated.
How do real-world applications handle complex routings?

Latest articles

spot_imgspot_img

Related articles

Leave a reply

Please enter your comment!
Please enter your name here

spot_imgspot_img