不同tableView部分中的核心数据对象

时间:2014-01-10 16:01:40

标签: ios uitableview core-data

我有一个带有可扩展/可折叠部分和固定部分标题的tableView,我想维护它。 这是执行此操作的代码:

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    return 6;
}


+ (NSString*) titleForHeaderForSection:(int) section
{
    switch (section)
    {
        case 0 : return @"Overdue";
        case 1 : return @"Today";
        case 2 : return @"Tomorrow";
        case 3 : return @"Upcoming";
        case 4 : return @"Someday";
        case 5 : return @"Completed";
       // default : return [NSString stringWithFormat:@"Section no. %i",section + 1];
    }
}

目前,我使用以下代码填充行:

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    switch (section)
    {
        case 2 : return 1;
        case 3 : return 30;
        default : return 8;
    }
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"Cell";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) 
    {
        cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease];
    }

    // Configure the cell.

    switch (indexPath.row)
    {
        case 0 : cell.textLabel.text = @"First Cell"; break;
        case 1 : cell.textLabel.text = @"Second Cell"; break;
        case 2 : cell.textLabel.text = @"Third Cell"; break;
        case 3 : cell.textLabel.text = @"Fourth Cell"; break;
        case 4 : cell.textLabel.text = @"Fifth Cell"; break;
        case 5 : cell.textLabel.text = @"Sixth Cell"; break;
        case 6 : cell.textLabel.text = @"Seventh Cell"; break;
        case 7 : cell.textLabel.text = @"Eighth Cell"; break;
        default : cell.textLabel.text = [NSString stringWithFormat:@"Cell %i",indexPath.row + 1];
    }

    //cell.detailTextLabel.text = ...;

    return cell;
}

但我想从核心数据实体填充行,这是我的NSFetchedResultsController:

- (NSFetchedResultsController *)fetchedResultsController {

    if (_fetchedResultsController != nil) {
        return _fetchedResultsController;
    }

    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    NSEntityDescription *entity = [NSEntityDescription
                                   entityForName:@"ToDoItem" inManagedObjectContext:self.managedObjectContext];
    [fetchRequest setEntity:entity];

    NSSortDescriptor *sort = [[NSSortDescriptor alloc]
                              initWithKey:@"tdText" ascending:NO];
    [fetchRequest setSortDescriptors:[NSArray arrayWithObject:sort]];

    [fetchRequest setFetchBatchSize:20];

    NSFetchedResultsController *theFetchedResultsController =
    [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
                                        managedObjectContext:self.managedObjectContext sectionNameKeyPath:nil
                                                   cacheName:@"Root"];
    self.fetchedResultsController = theFetchedResultsController;
    _fetchedResultsController.delegate = self;

    return _fetchedResultsController;

}

核心数据实体是'ToDoItem',我最终想要的是每个对象都出现在tableView的右边部分内。我需要你的帮助和建议。


为了使我的问题更加清晰,我将创建一个名为tdDate的属性,此属性应该是过滤键,以决定在哪个部分显示对象。考虑到具有当前日期的对象今天将出现在今天的部分下,明天它应出现在OVERDUE部分...

3 个答案:

答案 0 :(得分:1)

我能想到至少两种合理的策略。一种是进行多次单独的提取,每种类别一次。每个获取请求都将被赋予一个谓词,该谓词选择那些其到期日期和状态适合每个类别的ToDoItem个对象。例如,“今天”的获取请求将选择到期日为当前日期且状态不完整的项目; “已完成”的请求将忽略该日期并选择状态已完成的所有项目。

另一种策略是一次获取所有项目,并在获取后自行对其进行分类。这可能在概念上更简单,您仍然可以使用NSPredicate对对象进行分类。例如,您可以使用NSSet的-objectsPassingTest:方法或NSArray的-filteredArrayUsingPredicate:方法。

花些时间阅读using predicatesfetching objects

答案 1 :(得分:1)

一种很好的方法是在ToDoItem中添加一个新属性(例如state),您可以将sectionNameKeyPath用作NSFetchedResultsController

我将尝试用一个简单的例子来解释。

想一个列出食物的Food实体。此实体包含namecategory。 e.g。

Apple, Fruit
Banana, Fruit
Potato, Vegetable
Salad, Vegetable

如果您使用category作为sectionNameKeyPath,则会找到两个部分。一个将包含属于Fruit类别的食物,另一个将包含Vegetable类别的食物。

如果在您的实体中使用state属性,则同样适用(为简单起见,它是一个字符串,但您可以使用数字并使用地图将每个数字映射到字符串值)。我想这是正确的,因为每个项目都有一个完成状态。 此外,通过此方法,与每个state相关联的值可以动态更改。这应该是模型的一部分而不是控制器的一部分。 因此,state可以假定其中一个可能的值:@"Overdue"@"Today"@"Tomorrow"@"Upcoming"@"Someday"@"Completed"

作为一个重要的注释(参见Apple doc)

  

如果控制器生成节,则第一个排序描述符在   数组用于将对象分组为多个部分;它的关键必须要么   与sectionNameKeyPath或使用它的相对排序相同   key必须与sectionNameKeyPath匹配。

答案 2 :(得分:1)

您应该能够通过瞬态属性(例如itemState)对获取的结果进行分组,该属性计算ToDoItem应该出现的正确部分(即0 =过期,1 =今天,2 =明天)。

[[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
                                        managedObjectContext:self.managedObjectContext sectionNameKeyPath:@"itemState"
                                                   cacheName:@"Root"];

在您的托管对象中,实现itemState以返回项目的计算状态:

- (NSString *)itemState {
    // logic to return @"Overdue", @"Today", etc.. based on whatever logic makes sense in your app
    // see this on how to implement transient properties http://davemeehan.com/technology/objective-c/core-data-transient-properties-on-nsmanagedobject

}

然后你可以继续使用你的FRC来实现你的UITableViewControllerDataSource方法:

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return [[[self.fetchedResultsController sections] objectAtIndex:section] numberOfObjects];
}

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    return [self.fetchedResultsController sections].count;
}

...等......