Search code examples
iosswiftuiipadosswiftui-tabview

SwiftUI TabView seems to not respect @SceneStorage


I have an app that switches between TabView and Sidebar view depending on its sizeClass. The applicable code is below:

struct PoshBoardTabView : View {
    @Environment(\.horizontalSizeClass) var sizeClass

    @SceneStorage("lastTab") var lastTab: String?

    private let views: [TitledView]
    
    init(content: [TitledView]) {
        views = content
        lastTab = Tab.about.rawValue
    }
    
    var tabs: some View {
        TabView(selection: $lastTab) {
            ForEach(views, id: \.title) { item in
                item.view
                    .tabItem {
                        Text(item.title)
                        if item.systemImage {
                            Image(systemName: item.imageName)
                        } else {
                            Image(item.imageName)
                        }
                    }
                    .tag(item.title)
            }
        }
    }
    
    var sideBar: some View {
        NavigationView {
            List(selection: $lastTab) {
                ForEach(views, id: \.title) { item in
                    NavigationLink(destination: item.view, tag: item.title, selection: $lastTab) {
                        if item.systemImage {
                            Label(item.title, systemImage: item.imageName)
                        } else {
                            Label(item.title, image: item.imageName)
                        }
                    }
                    .tag(item.title)
                }
            }
            .listStyle(SidebarListStyle())
            .navigationTitle("PoshBoard")
        }
    }

    var body : some View {
        Group {
            if sizeClass == .compact {
                tabs
            } else {
                sideBar
            }
        }
        .onAppear(perform: {
            requestReview()
        })

    }
    
    func requestReview() {
        //TODO: turn on for release
        //                if let windowScene = UIApplication.shared.windows.first?.windowScene { SKStoreReviewController.requestReview(in: windowScene)
        //                }
    }    
}

Here is my problem:

When the app starts in regular width, the sidebar is shown and it displays the content for the LastTab selection. If I split the screen with another app that forces my app to go to compact width, then the window content switches to the content of the first tab. I want it to stay on whatever the last selected tab was.

I have put a breakpoint on the TabView line and $lastTab does show the correct value, but the TabView doesn't seem to respect it.


Solution

  • Turns out that the @SceneStorage variable should not be optional. Setting that to an initial value solves the problem of storing the state of the Tabs.

    Unfortunately, the list selection variable needs to be optional. So that can be fixed by creating an @State optional variable to hold that value. Have not yet figured out how best to update the lastTab SceneStorage variable.