Swiftui 不接收场景数据库更改

Swiftui 不接收场景数据库更改,swiftui,Swiftui,我正在尝试执行一些我以前放在我的应用程序委托中的代码,例如在进入后台时保存我的托管对象上下文。我将调用放在ScenePase的.onChange中,但没有得到任何结果。以下是一个示例项目: import SwiftUI @main struct PhaseApp: App { @Environment(\.scenePhase) private var scenePhase var body: some Scene { WindowGroup {

我正在尝试执行一些我以前放在我的应用程序委托中的代码,例如在进入后台时保存我的托管对象上下文。我将调用放在ScenePase的
.onChange
中,但没有得到任何结果。以下是一个示例项目:

import SwiftUI

@main
struct PhaseApp: App {
    @Environment(\.scenePhase) private var scenePhase
    
    var body: some Scene {
        WindowGroup {
            Text("Hello, world.")
        }
        .onChange(of: scenePhase) { phase in
            switch phase {
            case .active:
                print("Active")
            case .background:
                print("Background")
            case .inactive:
                print("Inactive")
            @unknown default: break
            }
        }
    }
}

每当我按下Home键或轻触应用程序时,我希望在模拟器或测试设备上获得打印命令,但什么也没有发生。

使用内部场景根视图(通常是
ContentView

使用Xcode 12/iOS 14进行测试

struct ContentView: View {
    @Environment(\.scenePhase) private var scenePhase
    var body: some View {
        TestView()
            .onChange(of: scenePhase) { phase in
                switch phase {
                    case .active:
                        print(">> your code is here on scene become active")
                    case .inactive:
                        print(">> your code is here on scene become inactive")
                    case .background:
                        print(">> your code is here on scene go background")
                    default:
                        print(">> do something else in future")
                }
            }
    }
}

您可以使用以下扩展名:

public extension View {
    func OnScenePhaseChange(phase: ScenePhase, action: @escaping () -> ()) -> some View
    {
        self.modifier( OnScenePhaseChangeModifier(phase: phase, action: action) )
    }
}

public struct OnScenePhaseChangeModifier: ViewModifier {
    @Environment(\.scenePhase) private var scenePhase
    
    public let phase: ScenePhase
    
    public let action: () -> ()
    
    public func body(content: Content) -> some View {
        content
            .onChange(of: scenePhase) { phase in
                if (phase == phase) {
                    action()
                }
            }
    }
}
最终用途:

ContentView()
     .OnScenePhaseChange(phase: .active)     { print("scene activated!") }
     .OnScenePhaseChange(phase: .background) { print("scene backgrounded!") }
     .OnScenePhaseChange(phase: .inactive)   { print("scene inactive!") }

我一直在使用Xcode 12 beta 3和iOS/iPadOS 14 beta 3进行测试,下面是我的发现。请注意,这其中很多都涉及到支持多个窗口,但是“SwiftUI生命周期”项目默认启用该功能,因此我怀疑您已经激活了它。在我最初的案例中,我将一个现有的SwiftUI应用程序从一个
SceneDelegate
移植到使用新的
app
struct,因此我已经有了多个窗口支持

以下是我在新测试应用程序中使用的测试
视图

struct ContentView:View{
@环境(\.scenePhase)私有变量scenePhase
var body:一些观点{
文本(“你好,世界!”).padding()
.onChange(of:scenePhase){phase in
开关相位{
案例.背景:
打印(“阶段更改:查看输入的背景”)
案件.现行:
打印(“阶段更改:视图输入激活”)
案例.非活动:
打印(“阶段更改:视图输入为非活动状态”)
@未知默认值:
打印(“阶段更改:视图进入未知阶段”)
}
}
}
}
(我在
应用程序
场景
中有相同的代码,但它们从不打印任何内容。)

  • 声明您可以在
    应用程序
    场景
    视图
    中声明
    onChange
    。在任何情况下,我都看不到
    应用程序
    场景
    级别的版本执行过,而且
    视图
    级别的版本似乎没有完全正确执行

  • 在不支持多个窗口的硬件上(我使用第7代iPod touch),每次执行
    视图
    级别关闭。(完全公开,这款iPod Touch仍在运行beta 2,但我认为这无关紧要。一旦我将其更新到b3,如果有关系,我会在这里提及。)编辑(这确实很重要。) 在不支持多个窗口(第7代iPod Touch)的运行beta 2的硬件上,我看到应用程序进入后台,回到前台,等等。在每次应用发布时,我都会看到“查看输入的活动”打印

  • 在支持多个窗口的硬件上(我使用的是带有Lightning接口的旧版iPad Pro),我看不到最初的场景创建。(第一次运行不会触发“View entered active”(查看已输入活动)消息。)我确实看到了后续的背景/前景转换。如果我从iPad多任务用户界面创建一个新场景,第二个场景将触发一个“查看输入活动”日志。不幸的是,我没有在iPad上针对beta 2运行此测试,所以我不能说b3是否改变了行为

  • 在运行iOS 14 beta 3的iPodtouch上,我看到了与iPad相同的行为:第一次启动时不会从视图中打印任何相位变化信息,但会报告后续的背景/前景变化

  • 在模拟器上,它总是表现得像iPad硬件,即使我在模拟iPodtouch。我怀疑这是因为模拟器在Mac电脑上运行,并以这种方式获得多窗口“支持”。但当我在模拟器中运行时,将应用程序放在后台时,我确实看到了一些消息,我只是错过了从实际硬件中获得的初始“View entered active”(查看进入活动)消息

  • 最后一点注意:当我从前台返回应用程序时,我首先看到“视图进入非活动状态”,然后看到“视图进入活动状态”。当我对应用程序进行背景设置时,我看到“查看已进入非活动状态”,然后是“查看已进入的背景”。我认为这是预期的行为,但由于其他部分似乎已损坏,我想提一下


    TL;博士:


    我认为您应该能够从
    视图中看到大多数
    场景库
    更改,但您将错过在iPad或模拟器上启动的初始应用程序。希望它们能像预期的那样在稍后的beta版中出现在
    App
    Scene
    对象中?

    由@Asperi给出的答案确实有效。但是场景扩展中有一个例子,在WindowGroup上调用onChange操作符。所以,我认为这是一个错误。如果我像这样使用它,所有的状态都会被触发!按照你在代码中写它们的顺序。我想如果(相位==相位)可能是问题所在。我重新命名了一个,效果更好。