将请求函数转换为通用类型

3

我正在尝试将我的下面的core data fetch请求代码转换为通用类型。

let request = NSPredicate(format: "name == %@ AND password == %@ AND type == %@", "admin", "admin", "admin")
let fetchReq : NSFetchRequest = UserRegistration.fetchRequest()
fetchReq.predicate = request
let adminDetail :[UserRegistration] = DatabaseEngine.fetch(fetchRequest: fetchReq)!

目前已转换:

extension UIViewController{
    class func getData<T: NSManagedObject>(req: NSPredicate) -> T{
        let fetchReq : NSFetchRequest = T.fetchRequest()
        fetchReq.predicate = req
        return DatabaseEngine.fetch(fetchRequest: fetchReq as! NSFetchRequest<NSManagedObject>)! as! T

    }
}

DatabaseEngine.fetch函数。

static func fetch (fetchRequest: NSFetchRequest<T> = NSFetchRequest(), context:NSManagedObjectContext = kApplicationDelegate.managedObjectContext) -> [T]? {

    let entity =  NSEntityDescription.entity(forEntityName: typeName(some:T.self)
        , in:context)
    // Configure Fetch Request
    fetchRequest.entity = entity
    do {
        return try  context.fetch(fetchRequest as! NSFetchRequest<NSFetchRequestResult>) as? [T]
    } catch {

        //let fetchError = error as NSError
        // return nil

    }
    return nil
}

但是再也没有结果了。有人能帮我用简洁的代码转换一下吗?感谢您的帮助。

@DávidPásztor,是的,它会准确地返回数组,请告诉我您是否可以修改此扩展及其类型。 - vaibhav
然后只需将返回类型设置为 [T]。但是,正如我已经说过的,如果没有看到 DatabaseEngine.fetch 的定义,我无法给出确切的答案。顺便说一句,强制解包返回值和强制转换似乎都不是一个好主意,除非您百分之百确定结果永远不会是 nil(在这种情况下,首先定义函数返回可选项就没有意义)。 - Dávid Pásztor
1
核心数据(Core Data)已经非常通用了。我建议使用协议(protocol)和协议扩展(protocol extension)(与UIViewController无关),限制为NSManagedObject并带有静态方法(static methods),所有NSManagedObject子类都可以采用。而将错误(throwing errors)转换为可选项(optionals),会使得智能错误处理变得更糟糕。请使用getData can throw并传递抛出的错误。 - vadian
@vadian,很高兴看到一个更好的示例来获取更多信息。 - vaibhav
我写了一个答案。 - vadian
显示剩余2条评论
1个回答

2
根据我的评论,我建议使用带有扩展的协议,例如:
protocol Fetchable
{
    associatedtype FetchableType: NSManagedObject = Self
    
    static var entityName : String { get }
    static var managedObjectContext : NSManagedObjectContext { get }
    static func objects(for predicate: NSPredicate?) throws -> [FetchableType]
}

extension Fetchable where Self : NSManagedObject
{
    static var entityName : String {
        return String(describing: self)
    }
    
    static var managedObjectContext : NSManagedObjectContext {
        return (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
    }
    
    static func objects(for predicate: NSPredicate?) throws -> [FetchableType]
    {
        let request = NSFetchRequest<FetchableType>(entityName: entityName)
        request.predicate = predicate
        return try managedObjectContext.fetch(request)
    }
}

(UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext 替换为您的托管对象上下文引用。

使所有 NSManagedObject 子类采用 Fetchable。在子类中不需要额外的代码。

现在,您可以使用以下代码获取数据:

do {
   let predicate = NSPredicate(format: ...
   let objects = try MyEntity.objects(for: predicate)
} catch {
    print(error)
}

这就是全部,对象[MyEntity],没有任何类型转换,在成功时始终是非可选的。

该协议可以轻松地通过默认排序描述符、排序方向等进行扩展。


Vadian,谢谢你的回答和解释,很棒。 - vaibhav
这个程序在 iOS 9 版本上不兼容,请建议将其兼容化,否则将毫无用处。 - vaibhav
我不知道在iOS 9中是否可以使用Swift 3通用的获取请求。如果可以,请不要替换获取请求行。 - vadian
好的,那么您只需要更改该行以获取托管对象上下文。 - vadian
没错,但是当我清除项目时,这会将NSManagedObject子类Fetchable从中移除。 - vaibhav
显示剩余10条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接