сцена неожиданно меняется
Я пытаюсь использовать новый протокол приложения для нового приложения SwiftUI, и мне нужно обнаружить изменение scenePhase в.background на уровне приложения, чтобы сохранить небольшие данные приложения в файле.plist. Я не знаю, ошибка это или я что-то делаю не так, но это не работает должным образом. Как только будет нажата кнопка, scenePhase изменится на.background, когда сцена все еще активна! Чтобы показать пример этого странного поведения, я показываю этот простой код:
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)")
}
}
}
Когда нажимается кнопка увеличения, scenePhase изменяется на.background, а затем, когда приложение действительно отправляется в фоновый режим, scenePhase не изменяется.
Я обнаружил, что перемещение.onChange (of: scenePhase) в View (ContentView) работает нормально, как я и ожидал, но Apple объявила, что вы можете отслеживать любое изменение scenePhase на уровне приложения, и это то, что я действительно хочу, а не на уровне просмотра.
3 ответа
Xcode12 beta 6, похоже, решает проблему. Теперь все работает как положено.
У меня также была аналогичная проблема, когда scenePhase вообще не работал, затем он работал, но не так, как ожидалось. Попробуйте удалить из своего ресурса только "@StateObject private", и вы, вероятно, получите другие результаты. Я надеюсь, что новые бета-версии исправят это.
Кстати, рекомендуемый способ сохранения небольших данных для всего приложения в SwiftUI 2+ - через оболочку свойств @AppStorage, которая сама опирается на UserDefaults. Вот как мы можем обнаружить первый запуск и переключить флаг:
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.")
}
}
}