skip to Main Content

Overview

  • On the iPad Portrait mode using @SceneStorage doesn’t show the detail screen, instead it shows the place holder screen.
  • Tapping on the back button then shows the restored detail screen

Problem

@SceneStorage successfully restores the value, however the problem is about the navigation stack after the value is restored.

Steps to Reproduce

  1. Run on iPad potrait
  2. Select the Car "bbb"
  3. See the Car Detail with the car name "bbb"
  4. Enter background
  5. Repeat steps 1 and 2

Actual Behaviour:

Notice the car name is not displayed, it shows the "No car selected" text, tapping on the back button then shows the CarDetail screen with the name "bbb"

Expected Behaviour: 

The shows the CarDetail screen should show with the name "bbb" immediately instead of showing the place holder screen

Note:

  • It works fine on iPhone potrait and iPad landscape
  • Problem is on iPad potrait and iPhone 13 Pro max landscape

GIF

Screen recording of the problem

Configuration

  • iPad OS 15.5
  • Xcode 13.4 (13F17a)
  • macOS 12.4 (21F79)

Code:

ContentView

struct ContentView: View {

    var body: some View {
        NavigationView {
            CarList()
            Text("No car selected")
                .font(.largeTitle)
        }
    }
}

CarList

struct CarList: View {
    
    let cars = [Car(id: 1, name: "aaa"),
                Car(id: 2, name: "bbb"),
                Car(id: 3, name: "ccc")]
    
    @SceneStorage("selectedCarID") private var selectedCarID: Int?
    
    var body: some View {
        List {
            ForEach(cars) { car in
                NavigationLink(tag: car.id, selection: $selectedCarID) {
                    CarDetail(name: car.name)
                } label: {
                    Text(car.name)
                }
            }
        }
    }
}

CarDetail

struct CarDetail: View {
    let name: String
    var body: some View {
        ZStack {
            Color.brown
            Text(name)
                .font(.largeTitle)
        }
    }
}

Car

struct Car: Identifiable {
    var id: Int
    var name: String
}

2

Answers


  1. The official docs on SceneStorage

    The system manages the saving and restoring of SceneStorage on your behalf. The underlying data that backs SceneStorage is not available to you, so you must access it via the SceneStorage property wrapper. The system makes no guarantees as to when and how often the data will be persisted.

    Each Scene has its own notion of SceneStorage, so data is not shared
    between scenes.

    Ensure that the data you use with SceneStorage is lightweight. Data of
    a large size, such as model data, should not be stored in
    SceneStorage, as poor performance may result.

    If the Scene is explicitly destroyed (e.g. the switcher snapshot is
    destroyed on iPadOS or the window is closed on macOS), the data is
    also destroyed. Do not use SceneStorage with sensitive data.

    I reproduced as you mentioned in the steps and saw the same behaviour.

    Also if you noticed switching the emulator back to portrait in iPhone 13 pro max and landscape in iPad Pro (12.9-inch) poof MAGIC the Car detail screens comes back automatically.

    So, I guess it’s a bug on apple’s side where SceneStorage is not working in certain orientation of some devices. Should let them know to fix it.

    Hope it helps.

    Login or Signup to reply.
  2. I faced such issue on iPhone 13 pro max in landscape position, it uses iPad behavior. Add .navigationViewStyle(.stack) for NavigationView for change behaviour.

    NavigationView {

    //content

    }.navigationViewStyle(.stack)

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search