user3581248
user3581248

Reputation: 1014

Generic core data fetch request

I am trying to create sort of a generic wrapper for simple core data fetches.

What I wanted to achieve, is, instead of writing multiple redundant methods that look like this:

func loadNSMOSubclass() -> [NSMOSubclass] {
    let fetchRequest: NSFetchRequest<NSMOSubclass> = NSMOSubclass.fetchRequest()
    do {
        let result = try mainContext.fetch(fetchRequest)
        return result
    }
    catch {
        return []
    }
}

I thought I could create a generic helper for that:

struct EntityLoader<T> where T: NSManagedObject {

   func loadEntity() -> [T] {
       let fetchRequest: NSFetchRequest<T> = T.fetchRequest()
       do {
           let mainContext = CoreDataState().mainContext
           let result = try mainContext.fetch(fetchRequest)
           return result
       }
       catch {
           return []
       }
    }
}

However, at that point the compiler has a weird error:

Cannot convert value of type NSFetchRequest<NSFetchRequestResult> to specified type NSFetchRequest<T>

where the suggested solution is even stranger, since everything compiles when I do a casting:

let fetchRequest: NSFetchRequest<T> = T.fetchRequest() as! NSFetchRequest<T>

That might be ugly, but I could live with that. However when I run this code I am getting a fatal error:

Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'executeFetchRequest:error: <null> is not a valid NSFetchRequest.'

Am I doing something wrong, or are these just some Swift's constraints that are currently impossible to surpass?

Upvotes: 4

Views: 1328

Answers (1)

Rukshan
Rukshan

Reputation: 8066

Problem here is fetchRequest() is a auto-generated helper function and it's only available for your NSManagedObject sub classes. It's not available for your generic type. Therefore, instead of using that function you have to use it's implementation with your generic type like this,

replace this line,

let fetchRequest: NSFetchRequest<T> = T.fetchRequest()

with this,

let fetchRequest: NSFetchRequest<T> = NSFetchRequest<T>(entityName: String(describing: T.self))

Upvotes: 5

Related Questions