NEW: Start my new Ultimate Portfolio App course with a free Hacking with Swift+ trial! >>

SOLVED: How to execute Core Data NSFetchRequest in a class method?

Forums > Swift

I have AppName.xcdatamodeld file, with Category in Entities. In Category I successfully add records from SwiftUI and successfully fetch them in View like so:

import SwiftUI
import CoreData

struct CategoriesList: View {
    @Environment(\.managedObjectContext) var moc

    var fetchRequest: FetchRequest<CountdownCategory>
    var countdownCategories: FetchedResults<CountdownCategory> {
        fetchRequest.wrappedValue
    }

    var body: some View {
        ForEach(countdownCategories, id: \.self) { countdownCategory in
            Text(countdownCategory.title ?? "Category")
        }
    }

    init() {
        fetchRequest = FetchRequest<CountdownCategory>(entity: CountdownCategory.entity(), sortDescriptors: [NSSortDescriptor(keyPath: \CountdownCategory.dateAdded, ascending: false)])
    }
}

Now I need to execute same query in different place of a program - not in SwiftUI view, but in a method in a class:

import Foundation
import CoreData

class Categories {
    func getCategories() {
        let moc = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType)
        let categoriesFetch = NSFetchRequest<NSFetchRequestResult>(entityName: "CountdownCategory")

        do {
            let categoriesFetch = try moc.fetch(categoriesFetch) as! [CountdownCategory]
        } catch {
            fatalError("Failed to fetch categories: \(error)")
        }

        // etc.
    }
}

I looked up sample code in official Core Data documentation, however when I try to execute this I get an error:

*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '+entityForName: nil is not a legal NSPersistentStoreCoordinator for searching for entity name 'CountdownCategory''

Would appreciate any help with fixing that error. My goal is to get data from Core Data from CountdownCategory in this method. (Swift 5.2)

UPD #1: when I use let categoriesFetch = CountdownCategory.fetchRequest() I get an error:

Ambiguous use of 'fetchRequest()'

UPD #2: when I use let categoriesFetch: NSFetchRequest<CountdownCategory> = CountdownCategory.fetchRequest() I do not get a crash. But how do I get data?

UPD #3: When using let moc = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext I get

Use of unresolved identifier 'UIApplication'

but import UIKit is present. Is it a problem with a build settings? Becasue if I run app without Build it does not crash...

   

Seems like your let moc = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType) context is not connected to the persistent store and so it does not know how to find the category.

   

@nemecek-filip how can I connect it to persistent store in this class?

   

I guess with @Environment(\.managedObjectContext) var moc but I know almost nothing about SwiftUI so...

   

@nemecek-filip thing is I don't need that in SwiftUI, in SwiftUI it works... I need to get data from request in a regular class.

   

Maybe I need to use same context I passed in to my SwiftUI environment object? But how to declare it in method?

   

hi,

let me answer your question (not so much to diagnose your code). i have a SwiftUI app where i use a class method outside of a View to execute a fetch. it looks like this for a Core Data entity named ShoppingItem as a class method on the ShoppingItem class itself:

import Foundation
import CoreData
import UIKit

extension ShoppingItem: Identifiable {

    fileprivate static var appDelegate: AppDelegate = {
        UIApplication.shared.delegate as! AppDelegate
    }()

  // other methods ...

    static func allShoppingItems() -> [ShoppingItem] {
        let context = appDelegate.persistentContainer.viewContext
        let fetchRequest: NSFetchRequest<ShoppingItem> = ShoppingItem.fetchRequest()
        do {
            let items = try context.fetch(fetchRequest)
            return items
        }
        catch let error as NSError {
            print("Error getting ShoppingItems: \(error.localizedDescription), \(error.userInfo)")
        }
        return [ShoppingItem]()
    }

  // other methods ...

}

this works fine (iOS 13 -- don't yet know how this will work with the new iOS 14 and SwiftUI App structure). feel free to look through my entire project, if you wish, on Github called ShoppingList.

hope that helps,

DMG

   

@delawaremathguy, thank you for your post.

I moved my method to another class which didn't use my app's Watch Extension in a Target Membership section and everything worked. I wish compiler said something like "UIApplication is not avaialbe on watchOS".

   

Subscribe to Hacking with Swift+

Sponsor Hacking with Swift and reach the world's largest Swift community!

Reply to this topic…

You need to create an account or log in to reply.

All interactions here are governed by our code of conduct.

 
Unknown user

Not logged in

Log in
 

Link copied to your pasteboard.