Document based macOS app with core data, swiftUI and several documents

I am trying to upgrade my document macos app with swiftui.. When starting Xcode creates the templates and everything works as expected as long as only one document is open. When 2 documents are open, and the app tries to do a @FETCH in the second document. It crashs...


Multiple NSEntityDescriptions claim the NSManagedObject subclass 'XXXXXXX' so +entity is unable to disambiguate


I assume that the are two managedobjectcontexts in the environment and the app can not identify which one.


Is it so? Has anyone the same problem? I would apreciate any idea on how to fix this? My apologies for asking it. I am relatively new to swiftui...

Replies

You need to provide a lot more information for anyone to help. Edit your question and add the following information:


  • List the steps you are taking to upgrade the app.
  • Explain what you mean by "Xcode creates the templates".
  • List the entity where you get the conflict and the NSManagedObject subclass.
  • Explain what you mean by "the app tries to do a @FETCH".


Are you using NSPersistentDocument? If not, you should be for a document-based Core Data Mac app.

Thanks for answering szymczyk I will try to answer your points:

  • The upgrade is no relevant as I've started from scratch
  • In XCode 11.4.1... New->Project->macOS->swiftUI & document-based application & use core data
  • For the last two points, I include the code...
// Documents.swift
    override func makeWindowControllers() {
        
        // Create the SwiftUI view and set the context as the value for the managedObjectContext environment keyPath.
        // Add `@Environment(\.managedObjectContext)` in the views that will need the context.
        let contentView = ContentView().environment(\.managedObjectContext, self.managedObjectContext!)
        
        // Create the window and set the content view.
        let window = NSWindow(
            contentRect: NSRect(x: 0, y: 0, width: 1050, height: 660),
            styleMask: [.titled, .closable, .miniaturizable, .resizable, .fullSizeContentView],
            backing: .buffered, defer: false)
        window.center()
        window.contentView = NSHostingView(rootView: contentView)
        window.makeKeyAndOrderFront(nil)
        let windowController = NSWindowController(window: window)
        
        self.addWindowController(windowController)

    }
// ContentView.swift

struct ContentView: View {
    
    @State private var selectedItem: Item?

    var body: some View {
        
        NavigationView {
            
             NavigationMaster(item: $selectedItem)

             if selectedItem != nil {
                NavigationDetail(item: $selectedItem) // The DrescriptionView is called from here
             }
             else {
                Text("Please select an item from the list").frame(maxWidth: .infinity, maxHeight: .infinity)
            }

            }.frame(minWidth: 800, minHeight: 400)
    }


// DescriptionView.swift
// The Text field is taken from the Parameters obect in core data... One record (name == "Name") is fetched
// updated when the moc is save

struct DescriptionView: View {

    @Environment(\.managedObjectContext) var moc
    
    @FetchRequest(
        entity: Parameter.entity(),
        sortDescriptors: [ NSSortDescriptor(keyPath: \Parameter.name, ascending: true),],
        predicate: NSPredicate(format: "name == %@", "Name")
    ) var parameter_name: FetchedResults<Parameter>
           
    @State private var name : String = ""

    var body: some View {
        
        Form{
            // Content
            VStack(alignment: .leading) {
                // Additional VStack to ensure is centrally aligned and the max width is 750
                VStack(alignment: .leading, spacing: 10) {

                    // Model section
                    Section(header: Text("Model").font(.headline).fontWeight(.light)) {
                        HStack {
                            Text("Name:").frame(width: 100.0, alignment: .leading)
                            TextField("", text:$name).frame(width: 300.0)
                        }
                        ).frame(width: 204.0)
                    }
                }.frame(width: 750, alignment: .leading)
                .padding(.top, 10)
            }            
        }.padding(20.0)
        .frame( maxHeight: .infinity, alignment: .top )
        .onAppear{
            self.name = self.parameter_name[0].valueString
        }
        .onDisappear{
            self.parameter_name[0].valueString = self.name
        }
    }
}


Please let me know if you need something else

I have not worked with Core Data in a SwiftUI app so I don't have a solution for you. I was advising you to provide more information because there wasn't enough in the original question for anyone to provide an answer.


I notice one thing missing. You supplied a lot of SwiftUI code but very little Core Data code. I see mentions of Item and Parameter. What are they? Are they Core Data entities? Provide more information about the Core Data entities and classes because your problem is more of a Core Data problem than a SwiftUI problem.

Here is the rest of the code for core data (standard)..


public class Parameter: NSManagedObject {

}

extension Parameter {

    @nonobjc public class func fetchRequest() -> NSFetchRequest<Parameter> {
        return NSFetchRequest<Parameter>(entityName: "Parameter")
    }

    @NSManaged public var name: String // Name is initializdz with an empty string
}