通用核心数据获取请求

use*_*248 4 generics core-data swift

我正在尝试为简单的核心数据获取创建一种通用包装器。

我想要实现的是,而不是编写如下所示的多个冗余方法:

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

我想我可以为此创建一个通用助手:

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 []
       }
    }
}
Run Code Online (Sandbox Code Playgroud)

然而,此时编译器出现了一个奇怪的错误:

无法将类型的值转换NSFetchRequest<NSFetchRequestResult>为指定类型NSFetchRequest<T>

建议的解决方案更奇怪,因为当我进行转换时,所有内容都会编译:

let fetchRequest: NSFetchRequest<T> = T.fetchRequest() as! NSFetchRequest<T>
Run Code Online (Sandbox Code Playgroud)

这可能很丑陋,但我可以忍受。但是,当我运行此代码时,我收到一个致命错误:

由于未捕获的异常“NSInvalidArgumentException”而终止应用程序,原因:“executeFetchRequest:错误: <null>不是有效的 NSFetchRequest。”

我是否做错了什么,或者这些只是 Swift 目前无法超越的一些限制?

sle*_*rfx 5

这里的问题fetchRequest()是自动生成的辅助函数,它仅适用于您的NSManagedObject子类。它不适用于您的通用类型。因此,您不必使用该函数,而是必须将其实现与您的泛型类型一起使用,如下所示,

替换这一行,

let fetchRequest: NSFetchRequest<T> = T.fetchRequest()
Run Code Online (Sandbox Code Playgroud)

有了这个,

let fetchRequest: NSFetchRequest<T> = NSFetchRequest<T>(entityName: String(describing: T.self))
Run Code Online (Sandbox Code Playgroud)