2017-08-30 11 views
0

私はコアデータモデルのデータマネージャを設計しています。クラスの親戚をフェッチする汎用関数を作成したいと思います。ジェネリック関数を使用してコアデータエンティティを取得する

各データタイプのマネージャを構築できるプロトコルを作成しました。このプロトコルでは、すでに2つの関連するタイプ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 } 
    } 
} 

答えて

0

私は1つの解決策を作成しました。 私たちは、特定のクラスとのすべての関係を識別することができます:それは(私たちは、同じ相対的なエンティティのための多くの関係を持つことができます)各関係する項目のすべてのIDを見つけるために私たちを可能に

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

を:

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 
} 

私はこれが最もエレガントなソリューションであることをわからないんだけど、それは

:-)作品
関連する問題