NSPersistentDocument FetchRequest warp property crash on macOS Document App SwiftUI project
This is due to emptiness of new document. As in any document-based application you have to prepare some default initial data for new document
Here is possible solution. Tested with Xcode 11.4 / iOS 13.4
in Document.swift
class Document: NSPersistentDocument {
// .. other code here
override func makeWindowControllers() {
// in case of new document create new empty book in context
// that will be shown in opened document window
let isNew = self.fileURL == nil
if isNew {
_ = Book(context: self.managedObjectContext!) // << here !!
}
let contentView = ContentView().environment(\.managedObjectContext, self.managedObjectContext!)
// ... other code here
Cannot load NSManagedObjectModel. nil is an illegal URL parameter
The problem is this line:
NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"FoodPin" withExtension:@"momd"];
modelURL
is nil
meaning that the system couldn't find the resource FoodPin.momd
.
Make sure you have a Core Data model in your project named FoodPin
. It will appear as FoodPin.xcdatamodeld
in the Project Navigator.
Multiple NSEntityDescriptions Claim NSManagedObject Subclass
Post-automatic-caching
This should not happen anymore with NSPersistent[CloudKit]Container(name: String)
, since it seems to cache the model automatically now (Swift 5.1, Xcode11, iOS13/MacOS10.15).
Pre-automatic-caching
NSPersistentContainer/NSPersistentCloudKitContainer
does have two constructors:
- init(name: String)
- init(name: String,
managedObjectModel model: NSManagedObjectModel)
The first is just a convenience initializer calling the second with a model loaded from disk. The trouble is that loading the same NSManagedObjectModel
twice from disk inside the same app/test invocation
results in the errors above, since every loading of the model results in external registration calls, which print errors once called a second time on the same app/test invocation
.
And init(name: String)
was not smart enough to cache the model.
So if you want to load a container multiple time you have to load the NSManagedObjectModel
once and store it in an attribute you then use on every init(name:managedObjectModel:)
call.
Example: caching a model
import Foundation
import SwiftUI
import CoreData
import CloudKit
class PersistentContainer {
private static var _model: NSManagedObjectModel?
private static func model(name: String) throws -> NSManagedObjectModel {
if _model == nil {
_model = try loadModel(name: name, bundle: Bundle.main)
}
return _model!
}
private static func loadModel(name: String, bundle: Bundle) throws -> NSManagedObjectModel {
guard let modelURL = bundle.url(forResource: name, withExtension: "momd") else {
throw CoreDataError.modelURLNotFound(forResourceName: name)
}
guard let model = NSManagedObjectModel(contentsOf: modelURL) else {
throw CoreDataError.modelLoadingFailed(forURL: modelURL)
}
return model
}
enum CoreDataError: Error {
case modelURLNotFound(forResourceName: String)
case modelLoadingFailed(forURL: URL)
}
public static func container() throws -> NSPersistentCloudKitContainer {
let name = "ItmeStore"
return NSPersistentCloudKitContainer(name: name, managedObjectModel: try model(name: name))
}
}
Old answer
Loading Core Data is a little bit of magic, where loading a model from disk and using it means it registers for certain types. A second loading tries to register for the type again, which obviously tells you that something registered for the type already.
You can load Core Data only once and cleanup that instance after each test. Cleanup means deleting every object entity and then saving. There is some function which gives you all entities which you can then fetch and delete. Batch delete is not available InMemory though so object-by-managed object it is there.
The (probably simpler) alternative is to load the model once, store it somewhere and reuse that model on every NSPersistentContainer
call, it has a constructor to use a given model instead of loading it again from disk.
Failed to find a unique match for an NSEntityDescription CoreData Swiftui
You loaded model several times - that's the reason of those errors. Possible solution is to make container static.
Tested with Xcode 12.1 / iOS 14.1 - no errors:
class OriEPS {
private static var persistentContainer: NSPersistentContainer = {
let container = NSPersistentContainer(name: "CDOriEPS")
container.loadPersistentStores { description, error in
if let error = error {
fatalError("Unable to load persistent stores: \(error)")
}
}
return container
}()
var context: NSManagedObjectContext {
return Self.persistentContainer.viewContext
}
// ... other code
Note: other possible approach is to make OriEPS
shared and use same instance everywhere you create it, but I did not investigate your solution deeply, so it is for your consideration.
Related Topics
Swift Find Superview of Given Class with Generics
Adding a Custom Font to MACos App Using Swift
How to Remove Top Space of 'Form' in Swiftui
Swift Packages and Conflicting Dependencies
Libicuuc.So.55: Cannot Open Shared Object File
Detect When Wkwebview Is Finished Loading
How to Implement Default Associated Values with Swift Enums
Xcode Takes Long Time to Print Debug Results
Swiftui Sheet Not Animating Dismissal on MACos Big Sur
Uirefreshcontrol() in iOS 11 Glitchy Effect
Why Does Using Dynamictype on a Force Unwrapped Nil Optional Value Type Work
Countforfetchrequest in Swift 2.0
How to Cast a Metaclass Object to a Protocol Type in Swift
"Use Default Container" Doesn't Show in Icloud Capabilities
Swift "Is" Operator with Type Stored in Variable
Search Multiple Words in One String in Swift