将 NSManagedObject 传递给子上下文不起作用

Posted

技术标签:

【中文标题】将 NSManagedObject 传递给子上下文不起作用【英文标题】:Passing NSManagedObject to child context not working 【发布时间】:2021-11-05 14:55:05 【问题描述】:

我是编程新手,如果有人能提供一个基本的解释,将不胜感激。

我正在尝试将已获取并与主视图上下文相关联的 NSManagedObject 传递给子上下文进行编辑。但是,我的详细视图中没有显示任何内容。由于某种原因,托管对象没有被传递。

// Content View, everything is showing up fine here

struct ContentView: View 
    let persistenceController = PersistenceController.shared
    @Environment(\.managedObjectContext) private var viewContext
    @StateObject var viewModel = ContentViewModel()
    @FetchRequest(
        sortDescriptors: [NSSortDescriptor(keyPath: \Person.name, ascending: true)],
        animation: .default)
    private var people: FetchedResults<Person>
    
    var body: some View 
        NavigationView 
            List 
                ForEach(people)  person in
                    NavigationLink(destination: EditView(viewModel: EditViewModel(persistenceController: persistenceController, person: person))) 
                        Text(person.name ?? "Unknown")
                        Text("\(person.objectID)")
                    
                
            

// EditViewModel 

struct EditViewModel 
    var person: Person
    let context: NSManagedObjectContext
    let persistenceController: PersistenceController
    
    init(persistenceController: PersistenceController, person: Person) 
        self.context = persistenceController.childViewContext()
        self.person = (persistenceController.childViewContext().object(with: person.objectID) as? Person)!
        self.persistenceController = persistenceController
    

// EditView - all person properties are nil

struct EditView: View 
    @State var viewModel: EditViewModel
    var body: some View 
        GeometryReader  proxy in
            ScrollView(.vertical) 
                VStack 
                    TextField("Name", text: $viewModel.person.name ?? "")
                    Button("print") 
                        print(viewModel.person.name)
                    
                

如果我未能提供足够的信息来生成最小可重复示例,请告诉我,我会添加更多信息。

提前致谢。

【问题讨论】:

这是一个.environment 变量,所以请改用@Environment(\.managedObjectContext) private var viewContext @Yrb 感谢您的回复。不幸的是,我不太确定您的意思...我在内容视图中做到了...我还需要在 EditView 中做到这一点吗?我如何指定它是我想要使用的子上下文? 当我第一次读到这篇文章时,我以为你想将 MOC 传递给子视图。我错过了儿童 MOC 参考。但是,是的,当您在EditView 中创建孩子时,您只需通过在EditView 中调用@Environment(\.managedObjectContext) private var viewContext 来引用EditView 中的MOC。你把它放在你需要 MOC 的任何视图中。 @Yrb 再次感谢您的回复。我试过了,但没有用...我尝试在 EditView 上使用 .environment 将子上下文也注入环境中,但仍然没有。 当您说“它不起作用”时,您的意思是它没有注入 MOC,或者您无法制作子 MOC? 【参考方案1】:

由于您是从内容视图创建视图模型并将其注入到您的编辑视图中,因此您不需要使用/传递您的 PersistenceController 类,而且由于您传递的是 Person 对象,因此我们也不需要 NSManagedObjectContext Person 对象具有对其上下文的引用。

所以我会像这样重写视图模型

struct EditViewModel 
    var person: Person
    let context: NSManagedObjectContext?
    let parentContext: NSManagedObjectContext

    init(person: Person) 
         guard let parentContext = person.managedObjectContext else 
             //no context is really bad and should never happen
             FatalError("Found a NSManagedObject that doesn't belong to a context")

         self.parentContext = parentContext 
         let childContext = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType)
         childContext.parent = parentContext

         guard let childPersopn = try? childContext.existingObject(with: person.objectID)) else  
             self.childContext = nil        
             self.person = person
             return
         
         self.context = childContext
         self.person = childPerson
    
    //...

我觉得视图模型是一个结构而不是一个类有点奇怪。您可以将其制成符合ObservableObject 的类,并在您的视图中将其声明为@StateObject

【讨论】:

以上是关于将 NSManagedObject 传递给子上下文不起作用的主要内容,如果未能解决你的问题,请参考以下文章

如何解决:上下文提供程序未将新的上下文值传递给子级

SwiftUI 将数组的元素作为绑定传递给子视图

为什么永远不应该将NSManagedObject实例从一个线程传递到另一个线程?

如何在Flask的构架中传递logger给子模块

为 segue 中传递的新 nsmanagedobject 释放分配的上下文

将 NSManagedObject 重新插入到 ManagedObjectContext