2017-08-30 1 views
0

Ich entwerfe einen Datenmanager für mein Core-Datenmodell und ich möchte eine generische Funktion erstellen, um Verwandte einer Klasse zu holen.Erhalte Core-Entity-Verwandte mit einer generischen Funktion

Ich habe ein Protokoll erstellt, das das Erstellen von Managern für jeden Datentyp ermöglicht. In diesem Protokoll habe ich bereits zwei assoziierte Typen T und K und einige einfache Funktionen definiert. Jetzt stehe ich bei einer Klassen-Verwandten-Methode - ich muss irgendwie angeben, dass T Verwandte hat. Ich habe vergeblich versucht, ein Protokoll zu erstellen, das diese Beziehung durch gegenseitige Eigenschaften anzeigt, so dass beide Klassen diesem Protokoll entsprechen könnten. Irgendeine Idee, ist es überhaupt möglich?

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 } 
    } 
} 

Antwort

0

Nun, ich habe eine Lösung erstellt. Wir können alle Beziehungen zu einer bestimmten Klasse identifizieren:

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

Es erlaubt uns, für jede Beziehung alle IDs eines Artikels zu finden (wir viele Beziehungen für die gleiche relative Entity haben kann):

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

So können wir diese IDs verwenden, um Datensätze aus einer anderen Klasse abzurufen.

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 
} 

Ich bin nicht sicher, dass dies die eleganteste Lösung, aber es funktioniert :-)

Verwandte Themen