【问题标题】:Get Core Data Entity relatives with a generic function使用通用函数获取核心数据实体亲属
【发布时间】:2017-08-30 14:20:04
【问题描述】:

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

我创建了一个协议,允许为每种数据类型构建管理器。在这个协议中,我已经定义了两个相关的类型 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 }
    }
}

【问题讨论】:

    标签: swift generics core-data swift-protocols


    【解决方案1】:

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

    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
    }
    

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-06-06
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多