2011-01-04 11 views
1

Ich lade meine App mit einer Eigenschaftsliste von Daten von einer Website. Diese Eigenschaftslistendatei enthält ein NSArray von NSDictionaries, das selbst ein NSArray von NSDictionaries enthält. Im Grunde versuche ich einen TableView der Restaurantmenükategorien zu laden, von denen jedes Menüpunkte enthält.So speichern Sie ein Array von NSManagedObjects in einem NSManagedObject

Meine Eigenschaftslistendatei ist in Ordnung. Ich bin in der Lage, die Datei zu laden und durch die Knotenstruktur zu scrollen, indem ich NSEntityDescriptions erstelle und in Core Data speichern kann. Alles funktioniert gut und erwartet, außer dass in meinem Menü Kategorie verwaltetes Objekt, habe ich eine NSArray von Menüelementen für diese Kategorie. Später, wenn ich die Kategorien hole, sind die Zeiger auf die Menüpunkte in einer Kategorie verloren und ich bekomme alle Menüpunkte. Soll ich Prädikate verwenden oder verfolgen Core Data meinen Objektgraphen für mich?

Kann jemand sehen, wie ich Core Data lade und den Fehler in meiner Logik aufzeige? Ich bin ziemlich gut mit entweder SQL und OOP selbst, bin aber etwas verwirrt von ORM. Ich dachte, dass ich nur Aggregation in meinen verwalteten Objekten verwenden könnte und dass das Framework die Zeiger für mich verfolgen würde, aber anscheinend nicht.

NSError *error; 
NSURL *url = [NSURL URLWithString:@"http://foo.com"]; 
NSArray *categories = [[NSArray alloc] initWithContentsOfURL:url]; 
NSMutableArray *menuCategories = [[NSMutableArray alloc] init]; 

for (int i=0; i<[categories count]; i++){ 
    MenuCategory *menuCategory = [NSEntityDescription 
      insertNewObjectForEntityForName:@"MenuCategory" 
      inManagedObjectContext:[self managedObjectContext]]; 

    NSDictionary *category = [categories objectAtIndex:i]; 
    menuCategory.name = [category objectForKey:@"name"]; 
    NSArray *items = [category objectForKey:@"items"]; 
    NSMutableArray *menuItems = [[NSMutableArray alloc] init]; 
    for (int j=0; j<[items count]; j++){ 
    MenuItem *menuItem = [NSEntityDescription 
      insertNewObjectForEntityForName:@"MenuItem" 
      inManagedObjectContext:[self managedObjectContext]]; 

    NSDictionary *item = [items objectAtIndex:j]; 
    menuItem.name = [item objectForKey:@"name"]; 
    menuItem.price = [item objectForKey:@"price"]; 
    menuItem.image = [item objectForKey:@"image"]; 
    menuItem.details = [item objectForKey:@"details"]; 
    [menuItems addObject:menuItem]; 
    } 
    [menuCategory setValue:menuItems forKey:@"menuItems"]; 
    [menuCategories addObject:menuCategory]; 
    [menuItems release]; 
} 

if (![[self managedObjectContext] save:&error]) { 
    NSLog(@"An error occurred: %@", [error localizedDescription]); 
} 

Antwort

0

Sie legen ein NSArray als n-Beziehung Objekt

NSMutableArray *menuItems = [[NSMutableArray alloc] init]; 
[menuCategory setValue:menuItems forKey:@"menuItems"]; 

, die die Probleme verursachen könnten. Relationships in Coredata werden (sollte eine Ausnahme? Werfen) immer unsortiert daher NSSets. Fügen Sie Ihren Entitäten eine sortierindexeigenschaft hinzu, um sie zu sortieren.

+0

Ich bin mir nicht sicher, ob ich eine sortIndex Eigenschaft hinzufügen möchte, da dies gegen den ganzen Punkt von ORM geht, oder es sollte. In Java zum Beispiel, wenn ich ein Objekt zu einer ArrayList hinzufüge, gehen sie in das Array in Indexreihenfolge. Wenn ich später auf diese ArrayList zugreife, erhalte ich das Objekt nach Index. So funktioniert auch NSMutableArrays. Wenn ich also den Kontext speichere, erwarte ich von Core Data, dass meine verwalteten Objekte und alle Sammlungen, auf die in meinen verwalteten Objekten verwiesen wird, in der Reihenfolge gespeichert werden, in der sie der Sammlung hinzugefügt wurden. Aber das ist nicht der Fall. Ich kann auch einfach zum relationalen Modell zurückkehren. –

+0

Martin du hast mein Problem gelöst. Sobald ich NSMutableArray in NSMutableSet änderte, funktionierte alles genau. Danke vielmals. –

0

Ich hatte das gleiche Problem. Es gibt 2 große Probleme mit der Verwendung von NSSet s und Core Data: Wenn Sie nicht eindeutige Objekte benötigen und sie bestellen müssen. Angenommen, Sie haben zwei Entitäten in Core Data: Professor und Student. Der Student nimmt 10 Kurse für einen Studiengang und Sie möchten eine (one-to-many) Beziehung vom Studenten zum Professor haben, damit die Kurse belegt werden. Außerdem kann derselbe Professor mehr als eine Klasse unterrichten. So habe ich das Problem überwunden. Erstellen Sie ein Binärdatenattribut (wir nennen es profData) in Schüler- und Geschäftswörterbüchern, die es ermöglichen, die Daten nach Bedarf zu rekonstruieren. Hinweis: Speichern Sie kein Array von Professoren, da diese von vs. NSObject erben. Das kann Probleme verursachen. Sie können die erforderlichen Methoden mit einer Kategorie verknüpfen. In diesem Beispiel habe ich eine Kategorie für Student mit dem Namen ProfList (Student+ProfList.h/m) erstellt. Dadurch bleibt der Code außerhalb der Unterklassen . Wenn sich meine Attribute in Core Data ändern, kann ich die Unterklassen automatisch neu generieren, ohne diesen Code zu löschen. Hier ist ein Beispielcode:

// Student+ProfList.h 

#import <Foundation/Foundation.h> 
#import <UIKit/UIKit.h> 
#import "Student.h" 
#import "Professor.h" 

@interface Student (ProfList) 
- (NSArray *)getStudentsFullList; 
- (void)storeStudentsFullList:(NSArray *)fullList; 
@end 

// Student+ProfList.m 

#import "Student+ProfList.h" 

@implementation Student (ProfList) 

- (NSArray *)getStudentsFullList 
{ 
    NSData *storedData = self.profData; 
    if (!storedData) return nil; 
    NSMutableArray *fullList = [[NSMutableArray alloc] init]; 

    // Retrieve any existing data 
    NSArray *arrayOfDictionaries = [NSKeyedUnarchiver unarchiveObjectWithData:storedData]; 

    // Get the full professor list to pull from when recreating object array 
    NSManagedObjectContext *context = [self managedObjectContext]; 
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:@"Professor"]; 
    NSSortDescriptor *alphaSort = 
    [[NSSortDescriptor alloc] initWithKey:@"name" 
           ascending:YES 
           selector:@selector(localizedCaseInsensitiveCompare:)]; 
    [fetchRequest setSortDescriptors:@[alphaSort]]; 
    NSSet *allProfessors = [NSSet setWithArray:[context executeFetchRequest:fetchRequest error:nil]]; 
    for (NSDictionary *dict in arrayOfDictionaries) { 
     NSPredicate *predicate = [NSPredicate predicateWithFormat:@"name LIKE %@", [dict objectForKey:@"name"]]; 
     NSSet *filteredSet = [allProfessors filteredSetUsingPredicate:predicate]; 
     Professor *newProfessor = [filteredSet anyObject]; 
     newProfessor.index = [dict objectForKey:@"index"]; 
     [fullList addObject:newProfessor]; 
    } 
    return fullList; 
} 

- (void)storeStudentsFullList:(NSArray *)fullList 
{ 
    NSMutableArray *encodedList = [[NSMutableArray alloc] init]; 
    for (Professor *professor in fullList) { 
     [encodedList addObject:@{@"index" : @([encodedList count]), @"name" : professor.name}]; 
    } 
    NSArray *encodedArray = [NSArray arrayWithArray:encodedList]; 
    NSData *arrayData = [NSKeyedArchiver archivedDataWithRootObject:encodedArray]; 
    self.profData = arrayData; 
} 

#pragma mark - Core Data 

- (NSManagedObjectContext *)managedObjectContext 
{ 
    NSManagedObjectContext *context = nil; 
    id delegate = [[UIApplication sharedApplication] delegate]; 
    if ([delegate performSelector:@selector(managedObjectContext)]) { 
     context = [delegate managedObjectContext]; 
    } 
    return context; 
} 

@end 

Sie speichern eine lokale Variable in einer View-Controller, dann senden Sie diese Nachricht an die Schüler beispielsweise, um die Liste zu bekommen und lokal für die Verwendung in einer Tabellenansicht oder was auch immer speichern.

Verwandte Themen