遍历多对多关系的价值观?

时间:2011-11-28 04:28:12

标签: iphone objective-c core-data nspredicate

当涉及遍历Core Data many-to-many relationships时,我是一个菜鸟(我已经阅读了很多关于此的线程和文档,所以除非它结束全部,请不要链接到文档或线程)。

我正在制作一个库存应用程序,目前有一个Core Data模型,其中包含“Thing”,“Category”,“Location”和“ThingLocation”(ThingLocation是一个同时包含Thing和Location的实体引用,但包括特定位置上的事物数量。还有many-to-many relationship个实体,我想填充我的UI。我精通GUI,所以这不是用户界面的问题,而是我如何使用(可能)NSPredicates收集信息。

例如:如果我显示的TableView包含Category实体的详细信息,那么我将如何使用Things实体中的Category填充它。

例如:如果我想显示UILabel,则会显示其中Thing的总量。 (即将每个Location上的所有金额相加。)

编辑:我希望能够使用NSFetchedResultsController!

1 个答案:

答案 0 :(得分:2)

我不确定你的问题是什么。因此,例如,您希望迭代所有类别和该类别中的所有内容,您将首先请求没有谓词的类别实体(这将返回所有类别对象)并迭代所有具有快速枚举的类别: / p>

//iOS 5 way of doing it
NSFetchRequest* request = [NSFetchRequest fetchRequestWithEntity:@"Category"];
NSArray* arrayOfObjects = [context executeFetchRequest: request withError: nil];
for (Category* cat in arrayOfObjects)
{
    //iterate over all the things in that category
    for (Thing* thing in cat.things){
    {
        //do something?
    }
}

首次使用类别中的内容填充tableview的示例

如果你有这个类别,你会很容易得到这样的东西:

NSSet* things= category.things;
//you can get it into an array by sorting it somehow or just get it like that.
NSMutableArray* things = [[category.things allObjects] mutableCopy];

您可以以非常正常的方式迭代它或将它们用作tableview的数据源。如果你没有这个类别,你需要一些东西来区分它,在这种情况下你可以像这样设置谓词:

NSFetchRequest* request = [NSFetchRequest fetchRequestWithEntity:@"Thing"];
NSPredicate* pred = [NSPredicate predicateWithFormat:@"(relationToCat.DestAtt = %@)",howToDestinguish];

这将返回连接到具有该属性的类别的所有事物。

对于您的第二个示例,您将设置NSPredicate以获取该特定Thing的所有ThingLocations。然后迭代它们并在位置处累加值。如果你想为每个类别执行此操作,那么它只需要从类别开始嵌套一些for循环。然后为每件东西获取所有ThingLocations,并为每个东西添加值。

我希望能回答你的问题。 To-Many关系只是集合,可以这样对待。我发现自下而上的思考有助于我形成谓词。我想我需要这个类别中的所有东西,所以我会设置Things的实体并将它连接回谓词中的类别。

编辑:NSFetchedResultsController示例 在声明超类后,在.h文件中将NSFetchedResultsControllerDelegate添加到已实现的代理中。

创建一个ivar:     @property(nonatomic,retain)NSFetchedResultsController * fetchedResultsController;

在实现方面,我看到了两种不同的方法,第一种是为在那里初始化它的属性编写自定义访问器,另一种是在viewDidLoad中执行它,无论是设置是如下:

NSFetchRequest *fetchRequest = [[[NSFetchRequest alloc] init] autorelease];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Thing" inManagedObjectContext:context];
NSPredicate* pred=[NSPredicate predicateWithFormat:@"(relToCat.something=%@)",something];
[fetchRequest setPredicate:pred];
[fetchRequest setEntity:entity];
[fetchRequest setFetchBatchSize:20]; //tells it how many objects you want returned at a time.

//this is for displaying the things in some sort of order. If you have a name attribute you'd do something like this
NSSortDescriptor *descriptor = [[[NSSortDescriptor alloc] initWithKey:@"name" ascending:YES] autorelease];
NSArray *sortDescriptors = [[[NSArray alloc] initWithObjects: descriptor, nil] autorelease];
[fetchRequest setSortDescriptors:sortDescriptors];

//this is the set up. If you put a sectionNameKeyPath it will split the results into sections with distinct values for that attribute
NSFetchedResultsController *frc = nil;
frc = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:context] sectionNameKeyPath:@"attribute that splits it into sections" cacheName:nil];
[frc setDelegate:self];
[self setFetchedResultsController:frc];
[frc release];
frc = nil;

//Tells it to start.
[fetchedResultsController performFetch:nil];

然后对于表视图委托方法,这是一件小事,如下:

-(NSString*)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section{

    return [[[fetchedResultsController sections] objectAtIndex:section] name];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView*)tableView {
        return [[fetchedResultsController sections] count];
}
- (NSInteger)tableView:(UITableView*)tableView numberOfRowsInSection:(NSInteger)section
{
        return [[[fetchedResultsController sections] objectAtIndex: section] numberOfObjects];
}
/* If you want the bar on the right with the names of the sections...
-(NSArray*) sectionIndexTitlesForTableView:(UITableView *)tableView{
    return [fetchedResultsController sectionIndexTitles];
}*/
-(UITableViewCell* )tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
        static NSString* ident=@"cellident";
    UITableViewCell *cell = [self.itemTable dequeueReusableCellWithIdentifier:ident]; 
    if (!cell) {
        cell = [[[UITableViewCell alloc] initWithStyle: UITableViewCellStyleDefault reuseIdentifier:ident] autorelease];
    }
    [self configureCell:cell atIndexPath:indexPath];
    return cell;
}
- (void) configureCell:(UITableViewCell*)cell atIndexPath:(NSIndexPath*)indexPath {
    NSManagedObject* item=[fetchedResultsController objectAtIndexPath:indexPath];
    //set up your cell somehow
    return cell;
}

您还需要为获取的结果控制器添加委托方法。它们都很简单,看起来像这样:

- (void)controllerWillChangeContent:(NSFetchedResultsController*)controller {
    [tableView beginUpdates];
}
- (void)controller:(NSFetchedResultsController*) controller didChangeSection:(id <NSFetchedResultsSectionInfo>)sectionInfo atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type
{
    NSIndexSet *set = [NSIndexSet indexSetWithIndex:sectionIndex];
    switch(type) {
        case NSFetchedResultsChangeInsert: [tableView insertSections:set  withRowAnimation:UITableViewRowAnimationFade];
            break;
        case NSFetchedResultsChangeDelete:
            [tableView deleteSections:set withRowAnimation:UITableViewRowAnimationFade];
            break;
    }
}
- (void)controller:(NSFetchedResultsController*)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath*)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath*)newIndexPath
{
    UITableView *tv = tableView;
    switch(type) {
        case NSFetchedResultsChangeInsert:
            [tv insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];

            break;
        case NSFetchedResultsChangeDelete:
            [tv deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];

            break;
        case NSFetchedResultsChangeUpdate:
            [self configureCell:[tv cellForRowAtIndexPath:indexPath] atIndexPath:indexPath];
            break;
        case NSFetchedResultsChangeMove:
            [tv deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
            [tv insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
            break;
    }

}
- (void)controllerDidChangeContent:(NSFetchedResultsController*)controller {
    [tableView endUpdates];
}

这将更新表格,如果在程序的其他部分添加了一个东西,如果谓词匹配,它将自动显示在表格上。