+entityForName: nil is not a legal NSManagedObjectContext parameter searching for entity name 'Account''
- (NSManagedObjectContext *)managedObjectContext
{
if (managedObjectContext != nil) return managedObjectContext;
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (coordinator != nil) {
managedObjectContext = [[NSManagedObjectContext alloc] init];
[managedObjectContext setPersistentStoreCoordinator:coordinator];
}
return managedObjectContext;
}
- You haven't provided a lazy loading implementation of
persistentStoreCoordinator
- so
coordinator
will always benil
- so you will always be returning
nil
from this method - which means you will always get the error above.
To explain the error:
+entityForName: nil is not a legal NSManagedObjectContext parameter searching for entity name 'Account'
It's not immediately obvious from reading it, but this means that nil
is not a legal thing to pass for the managed object context. On first reading, it looks like you're doing entityForName:nil
but that isn't the case.
To fix the problem, you will need to provide a valid persistent store coordinator. I have a small article here which explains just how little code you need to set up a core data stack, this may help you.
iOS: Swift: Core Data: Error: +entityForName: nil is not a legal NSManagedObjectContext parameter searching for entity name
When you set var fetchedResultsController
, your managedObjectContext
is still nil
. Therefore, your app crashes when you declare:
let entity = NSEntityDescription.entityForName("OneItemCD", inManagedObjectContext: self.managedObjectContext)
Make sure to set managedObjectContext
correctly before you call the previous line of code.
One more thing:
To use a Swift subclass of OneItemCD
with your Core Data model, prefix the class name in the Class field of the model entity inspector with the name of your module, just like this: "testTableViewCoreData.OneItemCD" (See more about Core Data and namespaces here).
Environment property wrapper throws +entityForName: nil is not a legal NSPersistentStoreCoordinator for searching for entity name
Short answer, Environment
needs the @
, it is a wrapper. What you are trying to do isn't a documented use of Environment
https://developer.apple.com/documentation/swiftui/environment
Long answer,
You haven't provided a Minimal Reproducible product but here is what I see
let viewContextValue = Environment(\.managedObjectContext).wrappedValue
It doesn't work because as you know the @Environment
isn't available at this point or you would just use viewContext
.
let controller = ContentViewController(managedObjectContext: viewContextValue)
I see what you are trying to do here but as stated above @Environment
just isn't available during init
self._controller = StateObject(wrappedValue: controller)
And this while it "works" on the surface it kind of defeats the virtues of StateObject
SwiftUI might create or recreate a view at any time, so it’s important
that initializing a view with a given set of inputs always results in
the same view. As a result, it’s unsafe to create an observed object
inside a view. Instead, SwiftUI provides the StateObject attribute for
this purpose. You can safely create a Book instance inside a view this
way:@StateObject var book = Book()
https://developer.apple.com/documentation/swiftui/managing-model-data-in-your-app
In my experience custom init
s in SwiftUI don't provide a reliable experience. I try to stay away from them as much as I can. If you have to do custom work upon init
do it in a class
as a ViewModel
/ViewController
that is also an ObservableObject
a View
shouldn't do any work.
If you want an alternative to what you want to do this see this SO question
All you need is
let persistenceController = PersistenceController.shared
Inside your ContentViewController
and initialize your StateObject
like this.
@StateObject private var controller: ContentViewController = ContentViewController()
Here is a sample where I used a FetchedResultsController
it has sections
import SwiftUI
import CoreData
class TaskListViewModel: ObservableObject {
let persistenceController = PersistenceController.previewAware()
@Published var fetchedResultsController: NSFetchedResultsController<Task>?
init() {
setupController()
}
func setupController() {
do{
fetchedResultsController = try retrieveFetchedController(sortDescriptors: nil, predicate: nil, sectionNameKeyPath: #keyPath(Task.isComplete))
}catch{
print(error)
}
}
func deleteObject(object: Task) {
persistenceController.container.viewContext.delete(object)
save()
}
func save() {
do {
if persistenceController.container.viewContext.hasChanges{
try persistenceController.container.viewContext.save()
objectWillChange.send()
}else{
}
} catch {
print(error)
}
}
}
//MARK: FetchedResultsController setup
extension TaskListViewModel{
func retrieveFetchedController(sortDescriptors: [NSSortDescriptor]?, predicate: NSPredicate?, sectionNameKeyPath: String) throws -> NSFetchedResultsController<Task> {
return try initFetchedResultsController(sortDescriptors: sortDescriptors, predicate: predicate, sectionNameKeyPath: sectionNameKeyPath)
}
private func initFetchedResultsController(sortDescriptors: [NSSortDescriptor]?, predicate: NSPredicate?, sectionNameKeyPath: String) throws -> NSFetchedResultsController<Task> {
fetchedResultsController = getFetchedResultsController(sortDescriptors: sortDescriptors, predicate: predicate, sectionNameKeyPath: sectionNameKeyPath)
//fetchedResultsController!.delegate = self
do {
try fetchedResultsController!.performFetch()
return fetchedResultsController!
} catch {
print( error)
throw error
}
}
func getFetchedResultsController(sortDescriptors: [NSSortDescriptor]?, predicate: NSPredicate?, sectionNameKeyPath: String) -> NSFetchedResultsController<Task> {
return NSFetchedResultsController(fetchRequest: getEntityFetchRequest(sortDescriptors: sortDescriptors, predicate: predicate), managedObjectContext: persistenceController.container.viewContext, sectionNameKeyPath: sectionNameKeyPath, cacheName: nil)
}
private func getEntityFetchRequest(sortDescriptors: [NSSortDescriptor]?, predicate: NSPredicate?) -> NSFetchRequest<Task>
{
let fetchRequest: NSFetchRequest<Task> = Task.fetchRequest()
fetchRequest.includesPendingChanges = false
fetchRequest.fetchBatchSize = 20
if sortDescriptors != nil{
fetchRequest.sortDescriptors = sortDescriptors
}else{
fetchRequest.sortDescriptors = [NSSortDescriptor(key: #keyPath(Task.dateAdded), ascending: false)]
}
if predicate != nil{
fetchRequest.predicate = predicate
}
return fetchRequest
}
}
struct TaskListView: View {
@StateObject var vm: TaskListViewModel = TaskListViewModel()
@State var taskToEdit: Task?
var body: some View {
if vm.fetchedResultsController?.sections != nil{
List{
ForEach(0..<vm.fetchedResultsController!.sections!.count){idx in
let section = vm.fetchedResultsController!.sections![idx]
TaskListSectionView(objects: section.objects as? [Task] ?? [], taskToEdit: $taskToEdit, sectionName: section.name).environmentObject(vm)
}
}.sheet(item: $taskToEdit, onDismiss: {
vm.save()
}){editingTask in
TaskEditView(task: editingTask)
}
}else{
Image(systemName: "empty")
}
}
}
struct TaskEditView: View {
@ObservedObject var task: Task
var body: some View {
TextField("name", text: $task.name.bound)
}
}
struct TaskListSectionView: View {
@EnvironmentObject var vm: TaskListViewModel
let objects: [Task]
@State var deleteAlert: Alert = Alert(title: Text("test"))
@State var presentAlert: Bool = false
@Binding var taskToEdit: Task?
@State var isExpanded: Bool = true
var sectionName: String
var body: some View {
Section(header: Text(sectionName) , content: {
ForEach(objects, id: \.self){obj in
let task = obj as Task
Button(action: {
taskToEdit = task
}, label: {
Text(task.name ?? "no name")
})
.listRowBackground(Color(UIColor.systemBackground))
}.onDelete(perform: deleteItems)
})
}
private func deleteItems(offsets: IndexSet) {
withAnimation {
deleteAlert = Alert(title: Text("Sure you want to delete?"), primaryButton: Alert.Button.destructive(Text("yes"), action: {
let objs = offsets.map { objects[$0] }
for obj in objs{
vm.deleteObject(object: obj)
}
//Because the objects in the sections aren't being directly observed
vm.objectWillChange.send()
}), secondaryButton: Alert.Button.cancel())
self.presentAlert = true
}
}
}
struct TaskListView_Previews: PreviewProvider {
static var previews: some View {
TaskListView()
}
}
previewAware()
is just a method that decides wether to pass the built-in preview
or shared
static func previewAware() -> PersistenceController{
if ProcessInfo.processInfo.environment["XCODE_RUNNING_FOR_PREVIEWS"] == "1" {
return PersistenceController.preview
}else{
return PersistenceController.shared
}
}
Related Topics
Sbstatusbarcontroller Instance
How to Force an App to Change Language in iOS/Objective-C
Tableview Cell How Do We Resize Cell in Swift Along with Image and Label
How to Handle Push Notifications If the Application Is Already Running
Coremotion Updates in Background State
How to Dismiss the iOS Keyboard
Duplicate Symbols for Architecture Arm64
Detect If the Application in Background or Foreground in Swift
Xcode 4: Creating a Uiview Xib, Not Properly Connecting
Capture Uiview and Save as Image
Undefined Symbols for Architecture I386: "_Objc_Class_$_Zipexception", Referenced From: Error
iOS 8 Uiactivityviewcontroller and Uialertcontroller Button Text Color Uses Window's Tintcolor
Xcode Debugger Doesn't Print Objects and Shows Nil, When They Aren'T
Why Is My iOS App Not Showing Up in Other Apps' "Open In" Dialog
iOS Is It a Static or a Dynamic Framework