сцена неожиданно меняется

Я пытаюсь использовать новый протокол приложения для нового приложения 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.")
            }
    }
}
Другие вопросы по тегам