【问题标题】:Core data objects in different tableView sections不同 tableView 部分中的核心数据对象
【发布时间】:2014-01-10 16:01:39
【问题描述】:

我有一个带有可展开/可折叠部分和固定部分标题的 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 的属性,该属性应该是过滤键,以决定在哪个部分显示对象。考虑到具有当前日期的对象今天将出现在 TODAY 部分下,明天它应该出现在 OVERDUE 部分下......

【问题讨论】:

    标签: ios uitableview core-data


    【解决方案1】:

    实现的一个好方法是在您的ToDoItem 中添加一个新属性(例如state),您可以将其用作sectionNameKeyPathNSFetchedResultsController

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

    想想列出食物的Food 实体。这个实体有一个name 和一个category。例如

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

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

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

    作为重要说明(请参阅 Apple 文档)

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

    【讨论】:

    • 谢谢,但在我的情况下,将对象分配到部分的关键可能每天都在变化。
    • @mvasco 你什么意思?
    • 我的意思是这些部分应该包含有日期的 ToDoItems(可能是一个名为 tdDate 的属性),这个属性可以用作过滤键来使分布成部分,但是我应该找到根据当前日期更新密钥的方法。
    • 考虑到您的回答,我创建了一个名为 tdDate 的新属性,其中包括 ToDoItem 的到期日期。现在我有两个问题:1.如何在 tableView 上显示对象,2.如何将它们过滤到部分(过期,今天,明天,...)我是真正的解决方案。
    • @mvasco 您能否打开一个新答案并将链接作为评论发布?如果可能的话我会帮忙的。谢谢
    【解决方案2】:

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

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

    花一些时间阅读using predicatesfetching objects

    【讨论】:

    • 您介意给我举个例子,说明如何用获取请求的结果替换当前使用 switch 循环的 cellForRowAtIndexPath 吗?
    • 假设您有一个数组,其中包含所有明天到期的项目。使用indexPath.row 作为数组的索引,例如:ToDoItem* item = tomorrowItems[indexPath.row]; cell.textLabel.text = item.title; 您可以将相同的策略应用于各个部分——也许您有一个数组,其中数组中的每个项目都在,并且特定部分的项目数组。然后您可以使用indexPath.section 获取正确的数组,然后使用indexPath.row 从该数组中获取项目:ToDoItem* item = (allItems[indexPath.section])[indexPath.row];
    • 我创建了一个名为 tdDate 的新属性,其中包括 ToDoItem 的到期日期。你能告诉我在 tableView 上显示对象并过滤它们以便包含在正确的部分中所需的代码吗?
    • 您可以通过填充-tableView:cellForRowAtIndexPath: 中的单元格来显示桌子上的对象,就像您正在做的那样。对不起,我没有时间为你写代码。如果您阅读我上面链接的文档,如何对项目进行分类应该很清楚。尝试一下,如果遇到问题,请在此处寻求帮助。
    【解决方案3】:

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

    [[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;
    }
    

    ...等等...

    【讨论】:

    • 我猜这不起作用,因为itemState会在请求检索到的对象中找到。
    • @flexaddicted 不确定你的意思?
    • @flexaddicted 哦,我想我明白你的意思了。因为他想要一组固定的部分,所以这不会按原样工作(例如,可能没有过期的项目,所以过期不会出现)。
    猜你喜欢
    • 1970-01-01
    • 2022-01-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-06-05
    • 1970-01-01
    相关资源
    最近更新 更多