通用FetchRequest

时间:2018-09-27 06:40:24

标签: swift generics nsmanagedobject

我有一个静态函数,它扩展了NSManagedObject以得到一个像这样的对象...

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
        }
    }
}    

我想要的语法是

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

并从进行调用的类中推断出类型...但是我不确定在这里可以代替通用类型

NSFetchRequest<M>(entityName: name)

NSFetchRequest<???>(entityName: name)

预先感谢

2 个答案:

答案 0 :(得分:1)

基于Passing generic Class as argument to function in swift建议的链接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
    }
}

答案 1 :(得分:0)

如果您不介意两次写MYUser,则可以删除type参数并指定类型,以便Swift可以推断M

extension NSManagedObject {

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

        guard let name = entity().name else { return nil }
        guard M.entity().propertiesByName[kvp.0] != nil else {
            print("\(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
        }
    }
}

// usage:
let user: MYUser? = MYUser.get(with: ("id", "SomeUserId"), in: context)

如果您不想重复写MYUser,那么我想不出任何解决方案。如果NSManagedObject是协议,则可以在其中使用Self