2012-05-14 7 views
5

Wir haben einen Repository-Layer für die Interaktion mit Core Data erstellt, die Methoden wie allItems(), addItem:(Item*)item haben, wobei item die NSManagedObject-Unterklasse ist. Wenn wir ein Element speichern müssen, rufen wir die Methode im Repository auf und übergeben die Unterklasseninstanz als Argument. Das funktioniert jedoch nicht, da wir den Initializer init nicht verwenden können und der Kontext im Repository verborgen ist.Wie transportiere ich die NSManagedObject-Unterklasse zwischen Klassen?

Was ist der beste Weg, um Objekte zu übertragen, wenn Sie eine solche Architektur haben? Macht ein ItemDTO eine Passage um eine Option? Oder gibt es bessere Möglichkeiten, dies zu lösen, wie zum Beispiel das nicht untergeordnete NSManagedObject überhaupt zu verwenden und einfach den Schlüssel/Wert zu verwenden, der funktioniert.

+0

Können Sie Ihr Problem etwas weiter erklären? Tritt das Problem auf, dass Sie neue verwaltete Objekte nicht außerhalb der Repository-Schicht erstellen können oder dass Sie die Objekte später nicht speichern können? – jrturton

+0

Das Problem ist, dass der Kontext innerhalb der Repository-Schicht "versteckt" ist und ich möchte das nicht außerhalb der Repository-Schicht leaken. Ich möchte das als einen soliden Punkt der Abstraktion verwenden. – LuckyLuke

+1

Sie wissen, dass jedes verwaltete Objekt einen Zeiger auf den Kontext des verwalteten Objekts hat? So ist diese bestimmte Katze aus der Tasche, irgendwie. – jrturton

Antwort

1

I schrieb kopiert ein Beispielprojekt, das den Kontext aus benutzerdefinierten Modellklassen versteckt: branch 10583736.

(es ist nicht Endfertigung Code, nur ein kurzes Beispiel, nicht erwarten, es mit Multithreading oder seltsame Fehler umgehen) ist

Ausblenden der Kontext zu benutzerdefinierten Klassen nur eine Frage der Methoden individuelle Definition von zu gehe mit jeder Situation um, in der du normalerweise den Kontext anfordern und verwenden wirst.

Sie können eine Klasse für die Schichtspeicher definieren ohne den Kontext aussetzt:

@interface DataStore : NSObject 

+ (id)shared; 

- (void)saveAll; 
- (NSEntityDescription *)entityNamed:(NSString *)name; 
/* more custom methods ... */ 
- (NSManagedObject *)fetchEntity:(NSEntityDescription *)entity withPredicate:(NSPredicate *)predicate; 

@end 

Ich schlage vor, einen gemeinsamen Vorfahren für alle Ihre benutzerdefinierten Modellklassen zu verwenden, um einige Tipparbeit zu sparen. Diese Klasse kann die einzige sein, die direkt mit DataStore interagiert. Es hat keinen Zugriff auf den Kontext.

@interface DataObject : NSManagedObject 

+ (NSString *)entityName; 
+ (NSEntityDescription *)entity; 
- (void)save; 
/* more custom methods ... */ 

@end 

Schließlich definiert Ihr Modell benutzerdefinierte Klassen jede Methode, die Sie wahrscheinlich Vorteil der Einnahme müssen, was von der übergeordneten Klasse zur Verfügung gestellt:

@interface Card : DataObject 

@property (nonatomic, retain) NSString * question; 
@property (nonatomic, retain) NSString * answer; 
@property (nonatomic, retain) Deck *deck; 

/* return a new card */ 
+ (Card *)card; 

/* more custom methods ... */ 

@end 

Der Master Zweig eine übliche Vorgehensweise hat die Klassen, in denen Modell erhalten Kontext und arbeiten damit.

3

Normalerweise möchten Sie, dass die Controller, die die -Unterklassen erstellen, einen Zeiger auf die NSManagedObjectContext haben. Auf diese Weise könnten Sie den Initialisierer tatsächlich aufrufen.

Das Problem mit dem, was Sie versuchen, ist, dass die Elemente nicht ohne den Kontext vorhanden sein können. Dies geschieht absichtlich, damit Core Data weiß, ob Sie über ein neues Objekt oder ein Objekt sprechen, das sich bereits im persistenten Speicher befindet.

Sie könnten DTOs verwenden, aber Sie würden mit vielen Duplizierungen enden, so dass es schnell hässlich wird. Meiner Meinung nach sollten Sie in Erwägung ziehen, Ihre Controller auf den Core Data-Kontext aufmerksam zu machen, damit sie die Elemente (verwaltete Objekte) entweder ordnungsgemäß abrufen oder initalisieren und im Wesentlichen NSManagedObjectContext als Repository-Ebene verwenden können.

Denken Sie daran, dass die NSManagedObjectContext IST eine Persistenz Abstraktionsschicht und Sie können es mit anderen persistenten Speicherimplementierungen sichern, wenn Sie möchten, einschließlich Ihrer eigenen custom ones.

5

Ich würde sagen, dass die Architektur, die Sie verwenden, nicht für Kerndaten geeignet ist. Um es weiter zu benutzen (was Sie tun sollten), müssen Sie eines von zwei Dingen tun. Ich gehe davon aus, dass Ihre "Repository-Schicht" als Singleton implementiert ist, oder zumindest, dass die Objekte, die neue verwaltete Objekte erstellen, Zugriff darauf haben.

  • Setzen Sie den Kontext Ihres verwalteten Objekts anderen Objekten aus, normalerweise als Eigenschaft auf Ihrer Repository-Ebene.
  • Lassen Sie Ihre Repository-Ebene initialisieren und geben Sie die Objekte für Sie zurück. Dies würde bedeuten, dass ein Entitätsname übergeben und ein neues verwaltetes Objekt des entsprechenden Entitätstyps oder der entsprechenden Entität zurückgegeben wird.
  • Wenn Sie feststellen, dass Sie sich gegen die Frameworks wehren und übermäßige Abstraktionen erzielen, tun Sie es falsch.

    +0

    Die letzte Option war gut, danke! Sehr schlau – LuckyLuke

    Verwandte Themen