Search code examples
swiftgenericsnsmanagedobject

Generic FetchRequest


I have a static function that extends NSManagedObject to get an object like so...

NSManagedObject.get(type: MYUser.self, with: ("id", "SomeUserId"), in: context)

extension NSManagedObject {

    static func get<M: NSManagedObject>(type: M.Type, with kvp: (String, CVarArg), in context: NSManagedObjectContext) -> M? {

     guard let name = entity().name else { return nil }
     guard M.entity().propertiesByName[kvp.0] != nil else { Assert("\(name) does not have \(kvp.0)"); return nil }

     let fetchRequest = NSFetchRequest<M>(entityName: name)
     fetchRequest.predicate = NSPredicate(format: "\(kvp.0) == %@", kvp.1)

     do {
            let object = try context.fetch(fetchRequest)
            if let foundObject = object.first { return foundObject }
            return nil
        } catch {
            return nil
        }
    }
}    

The syntax I would like is

MYUser.get(with: ("id", "SomeUserId"), in: context)

and to infer the Type from the class that made the call... but I'm unsure what to put in place of the generic here

NSFetchRequest<M>(entityName: name)

NSFetchRequest<???>(entityName: name)

Thanks in advance


Solution

  • Based on the link Passing generic Class as argument to function in swift suggested by Martin R

    protocol Managed where Self: NSManagedObject { }
    
    extension Managed where Self: NSManagedObject {
    
    static func get(with kvp: (String, CVarArg), in context: NSManagedObjectContext) -> Self? {
    
        guard let name = entity().name else { return nil }
        guard entity().propertiesByName[kvp.0] != nil else { Assert("\(name) does not have \(kvp.0)"); return nil }
    
        let fetchRequest = NSFetchRequest<Self>(entityName: name)
        fetchRequest.predicate = NSPredicate(format: "\(kvp.0) == %@", kvp.1)
    
        do {
            let object = try context.fetch(fetchRequest)
            if let foundObject = object.first { return foundObject }
            return nil
        } catch {
            return nil
        }
    }