【问题标题】:How to store array of NSManagedObjects in an NSManagedObject如何在 NSManagedObject 中存储 NSManagedObjects 数组
【发布时间】:2011-01-04 05:50:57
【问题描述】:

我正在使用来自网站的数据属性列表加载我的应用程序。这个属性列表文件包含一个 NSDictionaries 的 NSArray,它本身包含一个 NSDictionaries 的 NSArray。基本上,我正在尝试加载餐厅菜单类别的 tableView,每个类别都包含菜单项。

我的属性列表文件很好。我能够加载文件并循环通过创建 NSEntityDescriptions 的节点结构并能够保存到核心数据。除了在我的菜单类别托管对象中,我有一个用于该类别的菜单项的 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]);
 }

【问题讨论】:

    标签: iphone cocoa-touch orm core-data


    【解决方案1】:

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

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

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

    【讨论】:

    • 我不确定我是否要添加一个 sortIndex 属性,因为这违背了 ORM 的全部观点,或者应该。例如,在 Java 中,当我将对象添加到 ArrayList 时,它们会按索引顺序进入数组。稍后,当我访问该 ArrayList 时,我按索引检索对象。这也是 NSMutableArrays 的工作方式。因此,当我保存上下文时,我希望 Core Data 保存我的托管对象,并且我的托管对象中引用的任何集合都按照它们添加到集合中的顺序保存。但这种情况并非如此。我还不如回到关系模型。
    • 马丁你解决了我的问题。一旦我将 NSMutableArray 更改为 NSMutableSet,一切正常。非常感谢。
    【解决方案2】:

    我有同样的问题。使用NSSets 和Core Data 有两个主要问题:如果您需要不明确的对象并需要它们排序。例如,假设您在 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
    

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-27
      • 1970-01-01
      • 2019-08-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多