Search code examples
iosswiftgenericscore-datacasting

Error casting NSFetchRequest<T> to NSFetchRequest<NSFetchRequestResult> where T is generic NSManagedObject


I want to state that I am fairly new to Swift and I was exploring CoreData concepts. I tried to test with a ToDo list app which on welcome screen shows user created task categories and upon clicking on any category the user will see all the tasks in that group. I tried to create a generic class something like ToDoListViewController<T: NSManagedObject> and to implement functionality available for both view controllers(CategoryViewController, TaskViewController). In that class I created a function loadItems which takes a predicate as an argument and populates the page with items from a fetch request. So the code roughly looks like this:

class ToDoListViewController<T: NSManagedObject>: UITableViewController {

    func loadItems(predicate: NSPredicate? = nil) {
        let request: NSFetchRequest<T> = T.fetchRequest()
        
        if predicate != nil {
                request.predicate = predicate!
            }
        
        do {
            let items = try context.fetch(request)
            // Do something
        } catch {
            print("Error fetching items from context \(error)")
        }
    }
}

The issue is that when I try to compile I get error:

Cannot assign value of type NSFetchRequest<NSFetchRequestResult> to type NSFetchRequest<T>

when assigning request variable. But if I force cast NSFetchRequest<NSFetchRequestResult> to NSFetchRequest<T> like this:

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

everything works fine. Since The NSManagedObject documentation clearly states that it conforms to NSFetchRequestResult protocol, why do I have to force cast NSFetchRequest<NSFetchRequestResult> to NSFetchRequest<T>?


Solution

  • You have to cast the type because the generic type of NSFetchRequest – which is constrained to NSFetchRequestResult – can also be NSDictionary or NSNumber or NSManagedObjectID.

    Rather than making a generic type more generic I recommend to use a protocol with associated types like described here