【问题标题】:Fetching and sorting objects into sections获取对象并将其分类为部分
【发布时间】:2014-01-12 05:09:38
【问题描述】:

在我的 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];
    }
}

- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
    return [CollapsableTableViewViewController titleForHeaderForSection:section];
}

这部分工作正常,但现在我想用核心数据对象填充这些部分。 对于这部分,在获取结果之前,我有以下代码:

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    NSError *error = nil;
    if (![[self fetchedResultsController] performFetch:&error])
    {
        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
        abort();
    }


    switch (section)
    {
        case 2 : return 3;
        case 3 : return 30;
        default : return 3;
    }
}

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

填充这些部分也可以正常工作......但我真正的要求是使用来自核心数据实体的对象填充这些部分。这意味着,我必须替换这些行:

switch (section)
        {
            case 2 : return 3;
            case 3 : return 30;
            default : return 3;
        }

与其他代码行一起以获得节中的实际行数。 以及以下代码行:

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

替换为其他代码行来调用真实对象的属性。

我已经在 y 项目中包含了所有核心数据堆栈以及 NSFetchedResultsController。 核心数据实体有两个属性:tdText、tdDate。 固定部分与 tdDate 属性相关。

【问题讨论】:

  • 你似乎一次又一次地围绕着同样的问题 :-) - 但是如果你已经有一个获取的结果控制器,你为什么不在使用它数据源方法(numberOfSections、numberOfRowsInSection、cellForRowAtIndexPath、...)。你已经在stackoverflow.com/questions/20249098/… 中做到了,我(希望)展示了如何将项目分组为“今天”、“明天”等。
  • (续)我不想听起来粗鲁(我——当然还有其他人——如果可以的话,会有所帮助),但也许你可以尝试使用 对您之前的问题给出的答案(例如stackoverflow.com/questions/21048835/…),并更清楚地描述您的具体问题所在。
  • 谢谢@MartinR,你听起来并不粗鲁,我知道你愿意帮助我,但问题在于我。我只能遵循一些教程并对教程代码进行微小的更改。在你和其他人给我的一些答案中,我只理解了一半,在我的 iOS 级别,我需要更清晰的答案,我需要将我的问题分解成更小的部分以完全理解答案。我的问题的另一部分是英语不是我的母语,也许我没有用正确的词来解释我真正需要的东西。
  • @MartinR,我决定按照 Caleb 的建议创建六个单独的提取,每个类别一个(过期、今天、明天、某天、即将到来、已完成)。他们每个人都有一个给定的谓词来选择那些适合每个类别的对象。我已将它们编号为 frc1,frc2,...现在的问题是如何使用它们来分配每个部分的结果来代替我的 cellForRowAtIndexPath 方法中的当前开关循环?
  • 这是获取核心数据/FRC 等基础知识的好指南youtube.com/watch?v=G36_91H4CKE

标签: ios core-data


【解决方案1】:

在这个代码示例中(除了来自 MartinR 的出色建议之外),您在 -tableView: numberOfRowsInSection: 方法中获取数据。这是令人难以置信的费用,而且绝对是错误的地方。在您的应用程序的生命周期中,该方法会被调用数百次(如果不是数千次),您应该永远在那里执行提取。

其次,您在NSFetchedResultsController 上调用-performFetch: 一次。这通常在-viewDidLoad 中执行,理想情况下调用一次。从那里你可以再次询问NSFetchedResultsController about its current state; you don't call-performFetch:`。

至于其余的。在继续前进之前,您需要退后一步,填补您对 Objective-C 和 Core Data 知识的空白。这里的一些评价最高的人给了你很好的答案,而你没有充分利用它们。如果你继续沿着这条路走下去,人们就会停止帮助你。

在问另一个已经回答的问题之前,请充分利用您给出的建议。

【讨论】:

  • 感谢您的建议。在提出另一个已经回答的问题之前,我将尝试充分利用所提供的建议。我真的很感谢这里所有人的时间和努力。我是来学习的。
【解决方案2】:

首先将硬编码的内容放入一些更好的结构中,这样您就可以轻松地从 Core Data 中填充一些数据。

将以下内容添加到 viewController 的 .h 文件中

NSArray *sectionsArray;
NSMutableDictionary *sectionMenus;
BOOL                _searched;
BOOL                _loading;

在.m文件中添加以下内容

        #define REMINDER_OVERDUE  @"Overdue"
        #define REMINDER_TODAY    @"Today"
        #define REMINDER_TOMORROW @"Tomorrow"
        #define REMINDER_UPCOMING @"Upcoming"
        #define REMINDER_SOMEDAY  @"Someday"
        #define REMINDER_COMPLETE @"Complete"

        #define SEARCHING @"Searching..."


        - (void)viewDidLoad
        {
            [super viewDidLoad];

            // This dictionary will be used to store separate Arrays of records for each section using the section title as the key
            sectionMenus = [[NSMutableDictionary alloc] init];

            // These are the hard coded sections
            sectionsArray = [[NSArray alloc] initWithObjects: REMINDER_OVERDUE, REMINDER_TODAY, REMINDER_TOMORROW, REMINDER_UPCOMING, REMINDER_SOMEDAY, REMINDER_COMPLETE, nil];

            // We start by populating the sections with a single record containing the string "Searching..." so the user
            // will see that the section is busy searching for data to display
            [sectionMenus setObject:[[NSArray alloc] initWithObjects: SEARCHING, nil] forKey: REMINDER_OVERDUE];
            [sectionMenus setObject:[[NSArray alloc] initWithObjects: SEARCHING, nil] forKey: REMINDER_TODAY];
            [sectionMenus setObject:[[NSArray alloc] initWithObjects: SEARCHING, nil] forKey: REMINDER_TOMORROW];
            [sectionMenus setObject:[[NSArray alloc] initWithObjects: SEARCHING, nil] forKey: REMINDER_UPCOMING];
            [sectionMenus setObject:[[NSArray alloc] initWithObjects: SEARCHING, nil] forKey: REMINDER_SOMEDAY];
            [sectionMenus setObject:[[NSArray alloc] initWithObjects: SEARCHING, nil] forKey: REMINDER_COMPLETE];

            _searched = NO;
        }

        - (void)viewDidAppear:(BOOL)animated
        {
            [super viewDidAppear:animated];

            // Each time the view appears we check to see if a search has been done and if not then perform a search
            if (!_searched) {
                _searched=YES;
                [self getMenus];
            }
        }

        // tableView delegate methods to use the array and dictionary as the data sources
        - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
            return [sectionsArray count];
        }
        - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {

            return [[sectionMenus objectForKey:[sectionsArray objectAtIndex:section]] count];
        }
        - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
            return [[sectionsArray objectAtIndex:section] description];
        }
        - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
        {
            static NSString *simpleTableIdentifier = @"Cell";
            static NSString *inactiveTableIdentifier = @"InactiveTableItem";
            UITableViewCell *cell;

            NSObject *node =[[sectionMenus objectForKey:[sectionsArray objectAtIndex:[indexPath section]]] objectAtIndex:[indexPath row]];

            cell = [tableView dequeueReusableCellWithIdentifier:inactiveTableIdentifier];

            if (cell == nil) {
               cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:inactiveTableIdentifier];
            }

            cell.textLabel.text = [node description];

            return cell;
        }

        // This methods performs the queries to get the data for each section
        // and loads each section when its done (ideally should be done in background)
        - (void)getMenus
        {   
            _loading = YES;

            [self makeOverdueMenus];
            UITableView *tableView = (UITableView *)self.view;
            [tableView reloadSections:[[NSIndexSet alloc] initWithIndex:0] withRowAnimation:UITableViewRowAnimationAutomatic];


            [self makeTodaysMenus];
            [tableView reloadSections:[[NSIndexSet alloc] initWithIndex:1] withRowAnimation:UITableViewRowAnimationAutomatic];

            [self makeTomorrowsMenus];
            [tableView reloadSections:[[NSIndexSet alloc] initWithIndex:2] withRowAnimation:UITableViewRowAnimationAutomatic];

            _loading = NO;
            [tableView reloadData];
        }

        - (void)makeOverdueMenus {
            NSPredicate *predicate = [NSPredicate predicateWithFormat:@"dueDate < %@",[NSDate date]];

            [self makeMenu: REMINDER_OVERDUE predicate:predicate];
        }
        - (void)makeTodaysMenus {
            NSPredicate *predicate = [NSPredicate predicateWithFormat:@"dueDate >= %@ and dueDate < %@",[NSDate date], [NSDate date]];

            [self makeMenu: REMINDER_TODAY predicate:predicate];
        }
        - (void) makeTomorrowsMenus {
            NSPredicate *predicate = [NSPredicate predicateWithFormat:@"dueDate >= %@ and dueDate <= %@",[NSDate date], [NSDate date]];

            [self makeMenu: REMINDER_TOMORROW predicate:predicate];
        }

        // Helper function to get the section items and add them to the dictionary 
        - (void)makeMenu:(NSString*)section predicate:(NSPredicate*)predicate  {

                NSMutableArray *reminders = [[NSMutableArray alloc] init];
                [reminders addObjectsFromArray:[self getDataSimple];
                [sectionMenus setObject:reminders forKey:section];

        }

    // Simple method to fetch data from Core Data store
    - (NSArray*)getDataSimple {

       // replace this line with a core data query
       NSArray * results = [[NSArray alloc] initWithObjects:@"First Cell", @"Second Cell", @"Third Cell", nil];

       return results;

    }

【讨论】:

  • 谢谢,我需要一些时间来理解你给我看的这段代码。如果我需要进一步的帮助,我稍后会告诉你。再次感谢你。我想这就是我所需要的……我保证会从中吸取教训,不再重复我的问题……
  • 最难的部分可能是理解字典包含的内容。它有一个 KEY,它是 @"Today",然后它有与这个 KEY 关联的数据,它是一个 NSArray,包含像 @{@"First Cell"、@"Second Cell"、@"Third Cell"} 这样的行。因此 TableView 使用节标题从字典中获取数据数组。
  • 可能最容易从手动创建字典条目开始
  • 两个虚拟问题。 self.loading 行有错误,你放了一个名为 _todayStartDate 的变量,我想我必须按如下方式启动它:NSDate *todayStartDate = [NSDate date];??
  • 只需将 self.loading 替换为 _loading。而且您需要定义自己的谓词 - 匹配日期很复杂,因为日期包括毫秒,所以您可能永远不会得到匹配。首先使用 todayStartDate >= [NSDate date];对于所有这些,您可以在 tableView 显示一些数据后优化日期搜索。首先使用我刚刚添加到答案中的 getDataSimple 方法 - 用这个替换所有对 getData: 的调用。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-06-26
  • 1970-01-01
  • 2012-11-03
  • 1970-01-01
  • 2023-01-12
  • 2014-04-20
相关资源
最近更新 更多