当涉及遍历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!
答案 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];
}
这将更新表格,如果在程序的其他部分添加了一个东西,如果谓词匹配,它将自动显示在表格上。