未接收场景阶段更改

时间:2020-07-10 18:46:58

标签: swiftui

我正在尝试执行一些我以前放到我的应用程序委托中的代码,例如在进入后台时保存我的托管对象上下文。我已将呼叫放入场景阶段的.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或点击应用程序时,都会在模拟器或测试设备上获得打印命令,但是什么也没发生。

3 个答案:

答案 0 :(得分:5)

使用内部场景根视图(通常为#include <stdio.h> int main() { char a[1000] = {0}; float L; int flag; //read a line from input printf("Text:"); scanf("%[^\n]s", a); float word_count = 0; float letter_count = 0; int sent_count = 0; int idx = 0; // go through the line while (a[idx]){ // if next char is special char, then we found a sentence if(a[idx] == '.' || a[idx] == '?' || a[idx] == '!' || a[idx] == '\n') { sent_count++; idx++; } //skip spaces while(a[idx] && isspace(a[idx])) idx++; // if next char is a letter => we found a word /* if (a[idx]) word_count++;*/ flag =0; //skip the word, increment number of letters while(a[idx] && !isspace(a[idx]) && a[idx]!='.' && a[idx]!='?' && a[idx]!='!' && a[idx]!='\n'){ letter_count++; idx++; flag =1; } if(flag ==1 ) word_count++; } printf("word count = %f\nletter count = %f\n", word_count, letter_count); L = letter_count/word_count*100; printf("L= %.2f\n", L); printf("# of Sentences: %d\n", sent_count); }

在Xcode 12 / iOS 14上进行了测试。

ContentView

答案 1 :(得分:3)

我一直在使用Xcode 12 beta 3和iOS / iPadOS 14 beta 3进行测试,这就是我所发现的。请注意,其中很多涉及支持多个窗口,但是“ SwiftUI生命周期”将 default 项目设置为启用该窗口,因此我怀疑您已将其激活。在我的原始情况下,我将现有的SwiftUI应用从SceneDelegate移植到使用新的App结构,因此我已经激活了多个窗口支持。

这是我在新的测试应用中使用的测试View

struct ContentView: View {
    @Environment(\.scenePhase) private var scenePhase

    var body: some View {
        Text("Hello, world!").padding()
            .onChange(of: scenePhase) { phase in
                switch phase {
                case .background:
                    print("PHASECHANGE: View entered background")
                case .active:
                    print("PHASECHANGE: View entered active")
                case .inactive:
                    print("PHASECHANGE: View entered inactive")
                @unknown default:
                    print("PHASECHANGE: View entered unknown phase.")
                }
            }
    }
}

(我在AppScene中使用相同的代码,但它们从不打印任何内容。)

  1. ScenePhase documentation声称您可以在onChangeApp Scene中声明View 。在我可以设计的任何情况下,我都没有看到AppScene级别的版本能够执行,并且View级别的版本似乎不能完全正确地执行。

  2. 支持多个窗口的硬件上(我使用的是第七代iPod touch),View级闭包会每执行一次 时间。 (完整披露,此iPod Touch仍在运行beta 2,但我认为这无关紧要。一旦将其更新为b3,就可以在这里提及它。) 编辑< / strong>(这很重要。) 在运行不支持多个窗口的beta 2的硬件(第7代iPod Touch)上,我看到该应用程序进入后台,回到前台,依此类推。每次启动应用程序时,我都会看到“查看已输入有效”的打印内容。

  3. 在支持 的硬件上(我使用带有Lightning接口的较旧的iPad Pro)我看不到最初的场景创建。 (第一次运行不会 not 触发“查看输入激活”消息。)我确实看到了后续的背景/前景转换。如果我从iPad多任务UI创建新场景,则 second 场景将触发“查看输入的活动”日志。不幸的是,我没有针对beta 2在iPad上运行此测试,因此我无法确定行为是否随b3改变。

  4. 在运行iOS 14 beta 3的iPod Touch上,我看到的行为与iPad相同:第一次启动不会从视图中打印任何相变消息,但是会报告随后的背景/前景更改。

  5. 在模拟器上,即使我正在模拟iPod Touch,它的行为也始终像iPad硬件一样。我怀疑这是因为模拟器在Mac的引擎盖下运行,并且以这种方式获得了多个窗口“支持”。但是,当我在模拟器中运行该应用程序并置于后台时,我确实看到了消息,但我只是缺少了从实际硬件中获得的初始“查看输入的活动”消息。

最后一点:当我从前台退回一个应用程序时,我看到“输入的视图无效”,然后看到“输入的视图有效”。当我后台应用程序时,我看到“查看输入的背景不活跃”,然后显示“查看输入的背景”。我认为这是预期的行为,但由于其他部分似乎已损坏,因此我想提一下。


TL; DR:

我认为您应该可以看到{em {em}} {em {em}} ScenePhase的变化,但是您会错过iPad或iPad上最初启动的应用程序。模拟器。希望它们会在以后的Beta版中按预期显示给ViewApp对象吗?

答案 2 :(得分:0)

您可以使用以下扩展名:

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!") }