如何为所有实体编写简单的通用核心数据函数

时间:2017-06-05 08:42:39

标签: ios swift generics core-data

编辑:特别使用Swift Generics

我想为所有实体使用countAll()函数,我希望通过编写一个通用函数来实现这一点。

以下处理一个名为'Event'的实体,但我想处理一个名为'T'的实体。

我不确定如何编写这样的通用函数。有人可以帮忙吗?

func countAll() -> Int {
    let request: NSFetchRequest<Event> = Event.fetchRequest()
    do {
      return try persistentContainer.viewContext.count(for: request)
    } catch {
      XCTAssert(false, "Core Data failed to fetch with error: " + error.localizedDescription)
      return 0
    }
}

这是我遇到错误之前最接近的:

func count<T: NSFetchRequestResult>(entityName: String) -> Int {
    let request = NSFetchRequest<T>(entityName: entityName)
    do {
      return try persistentContainer.viewContext.count(for: request)
    } catch {
      XCTAssert(false, "Core Data failed to fetch with error: " + error.localizedDescription)
      return 0
    }
}

2 个答案:

答案 0 :(得分:3)

泛型函数的合适替代方法是协议扩展和类方法

protocol Fetchable
{
    associatedtype FetchableType: NSManagedObject = Self

    static var entityName : String { get }
    static func countAll(in persistentContainer: NSPersistentContainer) throws -> Int

}

extension Fetchable where Self : NSManagedObject, FetchableType == Self
{
    static var entityName : String {
        return NSStringFromClass(self).components(separatedBy: ".").last!
    }

    static func countAll(in persistentContainer: NSPersistentContainer) throws -> Int
    {
        let request = NSFetchRequest<FetchableType>(entityName: entityName)
        return try persistentContainer.viewContext.count(for: request)
    }
}

好处是你可以在类上调用方法,只需让你的NSManagedObject子类采用协议。

do {   
    try Event.countAll(in: persistentContainer)
} catch { print(error) }

答案 1 :(得分:2)

您可以传递托管对象类而不是NSFetchRequestResult 通用函数:

func countAll<T: NSManagedObject>(entity: T.Type) -> Int {
    let entityName = String(describing: entity)
    let request = NSFetchRequest<T>(entityName: entityName)
    do {
        return try thePersistentContainer.viewContext.count(for: request)
    } catch {
        print(error.localizedDescription)
        return 0
    }
}

let count = countAll(entity: YourEntity.self)

另一种方法是在NSManagedObject上定义扩展方法 (与How can I create instances of managed object subclasses in a NSManagedObject Swift extension?中的内容类似):

extension NSManagedObject {

    class func countAll() -> Int {
        let eName = String(describing: self)
        let request = NSFetchRequest<NSFetchRequestResult>(entityName: eName)
        do {
            return try thePersistentContainer.viewContext.count(for: request)
        } catch {
            print(error.localizedDescription)
            return 0
        }
    }
}

let count = YourEntity.countAll()