vicentube
vicentube

Reputation: 101

scenePhase changing unexpectedly

I am trying to use the new App protocol for a new SwiftUI App and I need to detect a scenePhase change into .background at App level in order to persist little App data into a .plist file. I don't know if it is a bug or I am doing something wrong but it doesn't work as expected. As soon as a button is tapped, scenePhase change to .background when the scene is still active! In order to show an example of this weird behaviour, I am showing this simple code:

class DataModel: ObservableObject {
    @Published var count = 0
}

@main
struct TestAppProtocolApp: App {
    @Environment(\.scenePhase) private var scenePhase
    @StateObject private var model: DataModel = DataModel()
    
    var body: some Scene {
        WindowGroup {
            ContentView().environmentObject(model)
        }
        .onChange(of: scenePhase) { newScenePhase in
            switch newScenePhase {
            case .active:
                print("Scene is active.")
            case .inactive:
                print("Scene is inactive.")
            case .background:
                print("Scene is in the background.")
            @unknown default:
                print("Scene is in an unknown state.")
            }
        }
    }
}

struct ContentView: View {
    @EnvironmentObject var model: DataModel
    
    var body: some View {
        VStack {
            Button(action: { model.count += 1 }) {
                Text("Increment")
            }
            .padding()
            Text("\(model.count)")
        }
    }
}

When the increment button is tapped, scenePhase changes to .background and then, when the App is really sent to background, scenePhase is not changed.

I found out that moving the .onChange(of: scenePhase) to the View (ContentView) works fine as I expect but Apple announced you can monitor any scenePhase change at App level and this is what I really want not at View level.

Upvotes: 3

Views: 1346

Answers (3)

vicentube
vicentube

Reputation: 101

Xcode12 beta 6 seems to solve the issue. Now it works as expected.

Upvotes: 0

Shengchalover
Shengchalover

Reputation: 804

By the way, the recommended way of persisting little App-wide data in SwiftUI 2+ is through @AppStorage property wrapper which itself rests on UserDefaults. Here is how we can detect the first launch and toggle the flag:

struct MainView: View {
@AppStorage("isFirstLaunch") var isFirstLaunch: Bool = true
var body: some View {
        Text("Hello, world!")
            .sheet(isPresented: $isFirstLaunch, onDismiss: { isFirstLaunch = false }) {
                Text("This is the first time app is launched. The sheet will not be shown again once dismissed.")
            }
    }
}

Upvotes: 0

Tom K
Tom K

Reputation: 11

I also had a similar issue with scenePhase not working at all, then it worked but not as expected. Try removing only "@StateObject private" from your property and you will probably have other results. I hope new betas will fix this.

Upvotes: 1

Related Questions