0

我已经为“基于文档的应用程序”制作了一个基于新的 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 上做了一些巧妙的缓存,即使我认为一切都是新创建的,也会将旧对象注入我的视图层次结构中?

4

1 回答 1

0

尝试将任何连线/实例化移动到文档组的第一个视图。如果该视图包含您希望共享文档窗口生命周期的 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)
    }
}
于 2021-05-07T21:55:57.387 回答