Management of multiple root views in SwiftUI

Hey guys,

I'm totally unexperienced in Swift coding and I'm doing my first steps using Swift Playgrounds on my macOS as well as on my iPadOS.

I'm setting up a simple App that can be divided in 4 main categories (Splash, Authentication, Content, Setup). Each category (except the Splash as the short intro when running the app) can have a NavigationStack (e. g. switching between login view, register view, forgott password view in authentication). So I thought about having a root view for each of them. My google research gave me lots of ways and hints but it's not clear at all for me if I should and how I should do this. I often read about a RootViewController but I guess that's UIKit stuff and nothing for SwiftUI. Then I read about delegates and such. Then, I read an article that exactly fits my goals and I just liked to get your opinion what you think about this way to solve my plan:

First of all, I define a separate class for a appRootManager:


final class appRootManager: ObservableObject {
    enum eRootViews {
        case Splash, Authentification, Content, Setup
    }
    @Published var currentRoot: eRootViews = .Splash
}

The main app file looks like this:


@main
struct MyApp: App {
    @StateObject private var oRootManager = appRootManager()
    
    var body: some Scene {
        WindowGroup() {
            Group {
                switch oRootManager.currentRoot {
                    case .Splash:
                        viewSplash()
                    case .Authentification:
                        viewLogin()
                    case .Content:
                        viewContent()
                    case .Setup:
                        viewSetup()
                }
            }
            .environmentObject(oRootManager)
            .modelContainer(for: [Account.self])
        }
    }
}

In each of the for root view files (e. g. Splash view) I make the appRootManager addressable and switch the root view by updating the enum value, like for example:


struct viewSplash: View {
    @EnvironmentObject private var oRootManager: appRootManager
    var body: some View {
        ZStack {
            Color.blue
                .ignoresSafeArea()
            Text("Hello World")
                .font(.title)
                .fontWeight(.semibold)
                .foregroundColor(.white)
        }
        .onAppear() {
            DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
                withAnimation(.spring()) {oRootManager.currentRoot = .Authentification}
            }
        }
    }
}

It works fine and does exactly what I like to have (when I run the app out of Swift Playgrounds). I'm just wondering why it does not work in the App Preview in Swift Playgrounds and this is why I'd like to have your opinion to the way I solve my plan.

I'm very happy for any feedback. Thanks a lot in anticipation!

Kind regards

Kevin

@KeRaBe To see live Previews, you could use the preview macro or a structure that conforms to the PreviewProvider protocol.

For example:

struct ContentView: View {
    @EnvironmentObject private var oRootManager: appRootManager
    
    var body: some View {
        Group {
            switch oRootManager.currentRoot {
            case .Splash:
                viewSplash()
            case .Authentification:
                viewLogin()
            case .Content:
                viewContent()
            case .Setup:
                viewSetup()
            }
        }
    }
}
    
    #Preview {
        ContentView()
    }

The following docs also cover SwiftUI previews in more depth, you should review these:

Dear DTS Engineer,

thank you very much for your fast reply and for the links attached. I will review them carefully the next days.

What do you basically think about the way I solve the issue with handling multiple root views? Is that a good way for iOS, iPadOS and macOS management of views? When using your example with a wrapping master view "ContentView" over all root views, I don't really have more than 1 root view anymore, but that should be no problem I think. Maybe that's the "normal" way of doing it, when it is needed for a working preview..

Management of multiple root views in SwiftUI
 
 
Q