SwiftUI DocumentGroup 和切换到后台

Posted

技术标签:

【中文标题】SwiftUI DocumentGroup 和切换到后台【英文标题】:SwiftUI DocumentGroup and switching to background 【发布时间】:2020-12-21 12:47:01 【问题描述】:

我已经为“基于文档的应用程序”制作了一个基于新的 SwiftUI 多平台目标的应用程序。 但是,我面临着奇怪的问题。只要应用程序在前台,它就可以正常工作。如果通过任务切换将其移至后台,然后再次移至前台,则会将突变保存到文档中,但 SwiftUI 视图不会接收突变。因此,每当您在 UI 中按下一个按钮来改变文档时,当您从磁盘重新加载文档时,您会看到没有发生任何变化。

所以我在想,我使用 ObservedObjects,一旦我移动到后台,它们可能会被踢出内存。这可能是我的错误的原因吗?

但后来我在 App 结构中添加了一个打印行。

import SwiftUI

@main
struct MyApp: App 

    fileprivate func myLogging(_ file: FileDocumentConfiguration<MyDocument>) -> some View 
        print("""
                    IT IS CALLED
            """)

        return MainView().environmentObject(BindingWrapper(file.$document))
    

    var body: some Scene 
        DocumentGroup(newDocument: MyDocument())  (file) in
            return myLogging(file)
        .commands  AppCommands() 
    

你猜怎么着......这个打印总是在一个突变被渲染之前执行。这是有道理的。因为file.$document 是一个绑定,如果你做了一个变异操作,绑定会警告苹果文件是脏的,但它也会使整个层次结构失效。一旦错误发生,此日志仍会​​打印!

所以在线 MainView().environmentObject(BindingWrapper(file.$document)) 我假设一切都是从头开始创建的。 BindingWrapper 是一个自定义类,用于转换可观察对象中的绑定。这是我担心的对象之一,他们可能会被释放。但如果它们是新创建的……它们应该一直在那里,对吧? 顺便说一句,这个对象归环境所有。所以它不应该被释放。

所以,现在我被困住了。 Apple 是否对绑定 / ObservedObjects 进行了一些巧妙的缓存,即使我认为一切都是新创建的,也会将旧对象注入我的视图层次结构中?

【问题讨论】:

【参考方案1】:

尝试将任何连线/实例化移动到文档组的第一个视图。如果该视图包含您希望共享文档窗口生命周期的 StateObject,它们将不会被重建。

在下面的示例中,一个 WindowStore 被容纳为一个 @StateObject,如所述。 App 中的 RootStore 创建了 WindowStore,其中包括自动售货服务并将其注册到托管的窗口数组中。两者都可以启用您的日志服务。 (对我来说,当@FocusedValue 失败时(即最顶层的文档不再是关键窗口),该数组可以帮助 WindowGroups 对特定文档进行操作。)

@main
struct ReferenceFileDoc: App 
    
    @StateObject var root: RootStore
    
    var body: some Scene 
        DocumentGroup  ProjectDocument()  editor:  doc in
            DocumentGroupRoot(
                window: root.makeWindowStore(doc.document),
                factory: SwiftUIFactory(root, doc.document)
            )
            .environmentObject(doc.document)
            .environment(\.documentURL, doc.fileURL)
            .injectStores(from: root)
        .commands  Menus(root: root) 

    .... other scenes ...
struct DocumentGroupRoot: View 
    
    @EnvironmentObject var doc: ProjectDocument
    @Environment(\.undoManager) var undoManager
    @Environment(\.documentURL) var url

    @StateObject var window: WindowStore
    @StateObject var factory: UIFactory
    
    var body: some View 
        passUndoManagerToDocument()
        factory.reference(window)
        return DocumentWindow(vm: factory.makeThisVM()) // Actual visible window
            .focusedValue(\.keyWindow, window)
            .focusedValue(\.keyDocument, doc)
            .onAppear  /// Tasks 
            .reportHostingNSWindow  [weak window] in
                window?.setWindow($0)
            
            .onChange(of: url)  [weak window] in window?.setFileURL($0) 
            .environmentObject(/// sub-state stores from WindowStore)
            .environmentObject(window)
            .environmentObject(factory)
    

【讨论】:

以上是关于SwiftUI DocumentGroup 和切换到后台的主要内容,如果未能解决你的问题,请参考以下文章

SwiftUI fileExporter 在 DocumentGroup 的工具栏修饰符中用作按钮修饰符时不存在

在 SwiftUI DocumentGroup macOS 中创建并打开一个新文档

如何使用 SwiftUI DocumentGroup 读取大文件而不制作临时副本?

Swift UI 2 DocumentGroup 获取导航栏按钮操作

SwiftUI - 使用按钮切换“收藏”动态项目

SwiftUI:切换和按钮的奇怪错误