如何在NSManagedObject中存储NSManagedObjects数组

时间:2011-01-04 05:50:58

标签: iphone cocoa-touch orm core-data

我正在使用网站上的数据属性列表加载我的应用。此属性列表文件包含NSDiction的NSArray,它本身包含NSDiction的NSArray。基本上,我正在尝试加载餐馆菜单类别的tableView,每个类别都包含菜单项。

我的财产清单文件没问题。我能够加载文件并循环创建NSEntityDescriptions的节点结构,并能够保存到Core Data。除了在我的菜单类别托管对象中,我有一个针对该类别的NSArray菜单项,一切都很好。稍后,当我获取类别时,类别中菜单项的指针将丢失,我将获得所有菜单项。我想是使用谓词还是Core Data会跟踪我的对象图?

任何人都可以看看我是如何加载核心数据并指出我逻辑中的缺陷的?我自己对SQL和OOP都很满意,但对ORM有点困惑。我认为我应该能够在我的托管对象中使用聚合,并且框架会跟踪我的指针,但显然不是。

 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]);
 }

2 个答案:

答案 0 :(得分:0)

您将NSArray设置为多对多关系对象

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

可能会导致麻烦。(应该抛出异常?)CoreData中的关系总是未排序,因此NSSets。将sortIndex属性添加到实体以进行排序。

答案 1 :(得分:0)

我有同样的问题。使用NSSet和核心数据有两个主要问题:如果您需要非独特的对象并需要它们进行排序。例如,假设您在Core Data中有2个实体:教授和学生。学生需要10个课程才能获得学位课程,并且您希望从学生到教授之间建立(一对多)关系,以便获得课程。此外,同一位教授可以教授不止一门课程。这就是我克服这个问题的方式。在学生和商店词典中创建二进制数据属性(我们将其称为profData),以便根据需要重建数据。注意:不要存储一系列教授,因为它们继承自NSManagedObjectNSObject。这可能会导致问题。您可以使用类别来限制所需的方法。在这个例子中,我在Student上创建了一个名为ProfList(Student+ProfList.h/m)的类别。这使代码远离NSManagedObject子类,因此如果我的Core Data中的属性发生变化,我可以自动重新生成子类而不会消除此代码。以下是一些示例代码:

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

您将局部变量存储在视图控制器中,然后将此消息发送到学生实例以获取列表并将其保存在本地以供在表视图或其他任何内容中使用。