程序问答   发布时间:2022-06-01  发布网站:大佬教程  code.js-code.com
大佬教程收集整理的这篇文章主要介绍了当应用程序进入后台时,SwiftUI 应用程序返回到第一个屏幕大佬教程大佬觉得挺不错的,现在分享给大家,也给大家做个参考。

如何解决当应用程序进入后台时,SwiftUI 应用程序返回到第一个屏幕?

开发过程中遇到当应用程序进入后台时,SwiftUI 应用程序返回到第一个屏幕的问题如何解决?下面主要结合日常开发的经验,给出你关于当应用程序进入后台时,SwiftUI 应用程序返回到第一个屏幕的解决方法建议,希望对你解决当应用程序进入后台时,SwiftUI 应用程序返回到第一个屏幕有所启发或帮助;

我在 SwiftUI 中构建了一个应用程序,但遇到了一个烦人的问题。

当应用出现时,应用会显示自定义启动屏幕,同时应用数据异步加载。完成后,应用程序的主视图将呈现给用户。一旦用户到达这一点,只要他们将应用拖回后台,导航堆栈就会无缘无故地弹回第一个启动屏幕。

以下是相关代码片段:

MyApp.swift

@main
struct Jam500App: App {
    
    @Environment(\.scenePhase) var lifecycle

    init() {
        //initial setup goes here
    }
    
    var body: some Scene {
        windowgroup {
                LaunchVIEw()
        }
    }
    
}

LaunchVIEw.swift

struct LaunchVIEw: VIEw {
    
    @Observedobject var control: LaunchVIEwControl = LaunchVIEwControl()
    
    var body: some VIEw {
        NavigationVIEw(content: {
            ZStack {
                //some vIEw hIErarchy                 
                Navigationlink(destination: RootVIEw(),isActive: $control.isReady,label: {EmptyVIEw()})

            }
            .onAppear(perform: {
                control.loadData()
            })
            .navigationbarTitle("")
            .navigationbarHIDden(true)
            .statusbar(hIDden: true)
        }).navigationVIEwStyle(StackNavigationVIEwStyle())
    }
    
}

LaunchVIEwControl.swift

final class LaunchVIEwControl: ObservableObject {
    
    @Published var isReady: Bool = false
    private var executing: Bool = false
    private let dataService = DataService.shared
    
    func loadData() {
        //runs all initial app setup needed before the app starts (asynchronously)
        guard !executing else {
            return
        }
        executing = true
        self.setupCoreData()
    }
    
    private func setupCoreData() {
        //Initialises CoreData with CloudKit (asynchronously)
        CloudCoreDataService.shared.setup { [weak self] in
            guard let self = self else { return }
            self.checkRequiresInitialData()
        }
    }
    
    private func checkRequiresInitialData() {
        self.dataService.requiresInitialDataSetup(onCompletion: { [weak self] (isrequired) in
            guard let self = self else { return }
            if isrequired {
                self.setupInitialData()
            } else {
                self.isReady = true
            }
        })
    }
    
    private func setupInitialData() {
        //Generates initial database if needed
        self.dataService.setupInitialData { [weak self] (_) in
            guard let self = self else { return }
            self.isReady = true
        }
    }
    
}

RootVIEw.swift

struct RootVIEw: VIEw {
    
    @Observedobject var control = RootVIEwControl()
    
    var body: some VIEw {
        HStack(spacing: 0) {
            //some vIEw hIErarchy
        }
        .navigationbarTitle("")
        .navigationbarHIDden(true)
        .statusbar(hIDden: true)
    }
    
}

有没有其他人在 Xcode 12.4 中遇到过这个问题?

解决方法

您可以应用两种解决方案(这是我想到的,不会引起很多变化):

1.注射

当您在视图中初始化“LaunchViewControl”类时:

@ObservedObject var control: LaunchViewControl = LaunchViewControl()

SwiftUI 在其视图被丢弃和重绘时会一次又一次地初始化此控制变量,因为 ObservedObjects 与 State 变量不同,并且 SwiftUI 不会跟踪它们的状态。

要尝试此操作,请取消注释“scenePhase”行并将“init”方法添加到“LaunchViewControl”,然后添加一些打印语句以了解发生了什么,或添加断点。

例如:

final class LaunchViewControl: ObservableObject {
    // ....
    init() {
        print("initialized")
    }
    // ....
}

您将在控制台上看到多个“初始化”日志。这意味着,您的“isReady”变量将一次又一次地被覆盖为“false”。

为了防止这种情况并保持生命周期事件,您可以使用基本注入。

例如,将您的“LaunchView”更改为:

struct LaunchView: View {
    
    // Change here
    @ObservedObject var control: LaunchViewControl
    
    var body: some View {
        NavigationView(content: {
            ZStack {
                //some view hierarchy
                Text("Launch")
                NavigationLink(destination: RootView(),isActive: $control.isReady,label: {EmptyView()})

            }
            .onAppear(perform: {
                control.loadData()
            })
            .navigationBarTitle("")
            .navigationBarHidden(true)
            .statusBar(hidden: true)
        }).navigationViewStyle(StackNavigationViewStyle())
    }
}

和您的“Jam500App”:

@main
struct Jam500App: App {
    
    @Environment(\.scenePhase) var scenePhase
    
    let launchViewControl = LaunchViewControl()
    
    var body: some Scene {
        WindowGroup {
            // Inject launchViewControl
            LaunchView(control: launchViewControl)
        }
    }
}

您现在应该看到您的第二个视图没有弹出,并且您还保留了生命周期事件。

2.状态对象

您可以将 ObservedObject 更改为“StateObject”,而不是执行所有这些操作,这将在视图丢弃和重绘时保持其状态。

更多信息

此外,SO 中已经有一些很好的答案,您可以查看 ObservedObject 及其工作原理。其中之一是this。另一个关于 StateObject 和 ObservedObject 的区别是 this。

为了在项目的后续步骤中防止出现这种情况,我会尝试使用 MVVM 方法,如果您想了解更多相关信息,可以使用非常棒的教程,例如 this。

大佬总结

以上是大佬教程为你收集整理的当应用程序进入后台时,SwiftUI 应用程序返回到第一个屏幕全部内容,希望文章能够帮你解决当应用程序进入后台时,SwiftUI 应用程序返回到第一个屏幕所遇到的程序开发问题。

如果觉得大佬教程网站内容还不错,欢迎将大佬教程推荐给程序员好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。
标签: