Reputation: 101
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
Reputation: 101
Xcode12 beta 6 seems to solve the issue. Now it works as expected.
Upvotes: 0
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
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