问题描述
如何使用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
可以避免您描述的问题。很难确定这是否正是您所需要的,但是由于您的代码创建了似乎不必要的重复项,因此看来很有可能。