使用通用函数

时间:2017-08-30 14:20:05

标签: swift generics core-data swift-protocols

我正在为我的Core Data模型设计一个数据管理器,我想创建一个通用函数来获取类的亲戚。

我创建了一个允许为每种数据类型构建管理器的协议。在这个协议中,我已经定义了两个相关的类型T和K以及几个简单的函数。现在我坚持使用类亲戚提取方法 - 我需要以某种方式表明T有K亲戚。我试图通过相互属性创建一些指示这种关系的协议是徒劳的,所以这两个类都可以符合这个协议。任何想法,甚至可能吗?

import Foundation
import CoreData

protocol DataManager {

    associatedtype T: NSManagedObject, NSFetchRequestResult
    associatedtype K: NSManagedObject, NSFetchRequestResult // Relative

    static var sharedInstance: Self { get }

    static func getAll(sorted: [NSSortDescriptor]?, context: NSManagedObjectContext) -> [T]?
    static func insert(item: T)
    static func update(item: T)
    static func clean()
    static func deleteById(id: String)

    // Relatives
    static func getRelatives(by: T) -> [K]?
    static func get(byRelative: K) -> [T]?
}

extension DataManager {

    static func getAll(sorted: [NSSortDescriptor]?, context: NSManagedObjectContext) -> [T]? {

        guard let fetchRequest: NSFetchRequest<T> = T.fetchRequest() as? NSFetchRequest<T> else { return nil }
        fetchRequest.sortDescriptors = sorted

        var results: [T]? = nil

        do {
            results = try context.fetch(fetchRequest)
        } catch {
            assert(false, error.localizedDescription)
        } //TODO: Handle Errors

        return results
    }
}


protocol Identifiable {
    typealias Identity = String
    var id: Identity? { get }
}


extension DataManager where Self.T: Identifiable {

    static func get(by id: T.Identity, context: NSManagedObjectContext) -> T? {

        guard let fetchRequest: NSFetchRequest<T> = T.fetchRequest() as? NSFetchRequest<T> else { return nil }

        fetchRequest.predicate = NSPredicate(format: "%K == %@", "id", id)

        var rawResults: [T]? = nil

        do {
            rawResults = try context.fetch(fetchRequest)
        } catch {
            assert(false, error.localizedDescription)
        } //TODO: Handle Errors


        if let result = rawResults?.first {
            return result }
        else { return nil }
    }
}

1 个答案:

答案 0 :(得分:0)

好吧,我已经创建了一个解决方案。 我们可以识别与特定班级的所有关系:

let relationships = T.entity().relationships(forDestination: K.entity())

它允许我们为每个关系找到项目的所有ID(我们可以为同一个相对实体建立多个关系):

let relativesIDs = item.objectIDs(forRelationshipNamed: relationship.name)

因此,我们可以使用这些ID从另一个类中获取记录。

static func getRelatives(of item: T, context:NSManagedObjectContext) -> [K]? {

    guard let fetchRequest: NSFetchRequest<K> = K.fetchRequest() as? NSFetchRequest<K> else { return nil }
    fetchRequest.fetchBatchSize = 100

    var results: [K]? = nil

    var resultSet: Set<K> = [] // doesn't allow duplicates

    let relationships = T.entity().relationships(forDestination: K.entity())

    for relationship in relationships {

        let relativesIDs = item.objectIDs(forRelationshipNamed: relationship.name)
        let predicate = NSPredicate(format: "self IN %@", relativesIDs)
        fetchRequest.predicate = predicate

        var batchResults: [K] = []

        do {
            batchResults = try context.fetch(fetchRequest)
        } catch {
            assert(false, error.localizedDescription)
        } //TODO: Handle Errors

        if batchResults.count > 0 { resultSet = resultSet.union(Set(batchResults)) }
    }

    if resultSet.count > 0 { results = Array(resultSet) }

    return results
}

我不确定这是最优雅的解决方案,但它有效: - )

相关问题