如何使用SwiftUI在模式视图中创建NSManagedObject?

问题描述

如何使用SwiftUI在模式视图中创建新的Managedobject(MO)?

遇到一个奇怪的错误,其中Xcode占用GB的内存,并通过交换文件填充Mac上的硬盘。

当在.sheet修饰符中创建模态视图时,似乎会出现某种无限循环,该循环将注入到该模态视图中的Managedobject的副本填充内存。

此示例项目至少说明了部分问题。如果运行它,则会看到.sheet修饰符中调用方法反复触发。有一种理论认为,显示Managedobjects列表的屏幕下方会导致两个屏幕之间出现某种循环。

https://github.com/sphericalwave/ChildContextTest

希望在模式屏幕中使用childContext,因此如果在不保存childContext的情况下取消了模式视图,则所有未保存的更改都将被丢弃。但是需要首先清除此障碍,并且跨上下文共享Managedobject涉及一些挑战。

import CoreData
import SwiftUI

struct CrtFdsUI: View
{
    @Environment(\.managedobjectContext) var moc
    @FetchRequest(entity: CrtFd.entity(),sortDescriptors: [NSSortDescriptor(keyPath: \CrtFd.scale,ascending: true)])
    var crtFds: FetchedResults<CrtFd>
    @State var showModal = false
    @Observedobject var absFd: AbsFd
    
    func crtFdModal() -> CrtFdUI {
        print("func crtFdModal() -> CrtFdUI")
        let cF = CrtFd(scale: 1.0,absFd: absFd,moc: moc)
        return CrtFdUI(crtFd: cF)
    }
    
    var body: some View {
        NavigationView {
            vstack {
                List {
                    ForEach(self.crtFds,id: \.objectID) {
                        CrtFdCell(crtFd: $0)
                    }
                }
                .navigationBarTitle("CrtFdsUI")
                .navigationBarItems(trailing: PlusBtn(showModal: $showModal))
            }
            .sheet(isPresented: $showModal) { self.crtFdModal() }  //FIXME: Called in endless loop?
        }
    }
}

这是Managedobjects的列表。

import CoreData
import SwiftUI

struct CrtFdsUI: View
{
    @Environment(\.managedobjectContext) var moc
    @FetchRequest(entity: CrtFd.entity(),id: \.objectID) {
                        CrtFdCell(crtFd: $0)
                    }
                }
                .navigationBarTitle("CrtFdsUI")
                .navigationBarItems(trailing: PlusBtn(showModal: $showModal))
            }
            .sheet(isPresented: $showModal) { self.crtFdModal() }
        }
    }
}

解决方法

现在,每次重新计算视图层次结构时,代码都会创建一个[0,4]的新实例。这可能不是一个好主意,因为可能会由于您无法直接控制的原因而意外地重新计算层次结构,因此即使没有无限的创建循环,您最终仍可能会得到比您想要的更多的新托管对象。

我下载了您的项目,但不确定这两个Core Data实体代表什么,但是我确实注意到,[4]第一次出现时,其CrtFd已经具有{{1 }}属性,并且CrtFdsUI属性是一对多而不是一对多。这意味着当您在此代码中创建新实例时,您将一个absFd替换为另一个完全相同的副本。

我猜您真的不希望用相同的副本替换一个实例,因此,避免问题的一种方法就是更改您的crtFd以使用已经存在的实例存在,并且仅在没有副本的情况下创建一个新副本:

crtFd

可以避免您描述的问题。很难确定这是否正是您所需要的,但是由于您的代码创建了似乎不必要的重复项,因此看来很有可能。