如何使用NSPredicate在NSDate中按天分组 - 需要创建多个UITableView部分

时间:2013-02-18 18:25:47

标签: ios sql uitableview core-data

另见

  

Core Data Sort By Date With FetchedResultsController into sections

有没有办法按日期对CoreData实体中的对象进行分组,并使用它们在UITableView控件上创建多个部分?

基本上,我需要一些等同于以下伪SQL的东西,其中my_group_criteria()按天分组所有测试:

SELECT * FROM tests GROUP BY my_group_criteria(date)

例如,查询会将以下行分为3个单独的部分:

[test1 | 2013-03-18 15.30.22]
[test2 | 2013-03-18 14.30.22]
[test3 | 2013-03-18 13.30.22]

[test4 | 2013-03-17 18.30.22]
[test5 | 2013-03-17 19.30.22]

[test6 | 2013-03-15 20.30.22]

正如2中已经回答的那样,NSPredicate不适用于对实体进行分组,因此这可能不是最佳选择。

鉴于此,我如何根据类似于SQL GROUP BY的标准在UITableView中创建多个部分?

如果可能的话,我想避免直接访问SQL-lite数据库。

相关问题1:     NSPredicate: filtering objects by day of NSDate property

相关问题2: NSPredicate something equivalent of SQL's GROUP BY

2 个答案:

答案 0 :(得分:13)

您可以根据需要从Apple Developer Library修改DateSectionTitles示例项目。

首先,您必须修改临时sectionIdentifier属性的访问者函数,以根据年+月+日(而不是仅年+月)创建节标识符:

- (NSString *)sectionIdentifier {

    // Create and cache the section identifier on demand.

    [self willAccessValueForKey:@"sectionIdentifier"];
    NSString *tmp = [self primitiveSectionIdentifier];
    [self didAccessValueForKey:@"sectionIdentifier"];

    if (!tmp) {
        /*
         Sections are organized by month and year. Create the section identifier
         as a string representing the number (year * 10000 + month * 100 + day);
         this way they will be correctly ordered chronologically regardless of
         the actual name of the month.
         */
        NSCalendar *calendar = [NSCalendar currentCalendar];

        NSDateComponents *components = [calendar components:(NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit)
                               fromDate:[self timeStamp]];
        tmp = [NSString stringWithFormat:@"%d", [components year] * 10000 + [components month] * 100  + [components day]];
        [self setPrimitiveSectionIdentifier:tmp];
    }
    return tmp;
}

其次,必须更改titleForHeaderInSection委托方法,但想法是相同的:从部分标识符中提取年,月和日,并从中创建标题标题字符串:

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

    id <NSFetchedResultsSectionInfo> theSection = [[fetchedResultsController sections] objectAtIndex:section];

    NSInteger numericSection = [[theSection name] integerValue];
    NSInteger year = numericSection / 10000;
    NSInteger month = (numericSection / 100) % 100;
    NSInteger day = numericSection % 100;

    // Create header title YYYY-MM-DD (as an example):
    NSString *titleString = [NSString stringWithFormat:@"%d-%d-%d", year, month, day];
    return titleString;
}

答案 1 :(得分:0)

假设想法是将对象数组分组为一组对象数组,我将采用的方法是,首先找到日期的可能值(或者你想要分组的任何值),然后实际排序它出来了。

NSArray *values = ...;
NSArray *sorting = [values valueForKey:@"@distinctUnionOfObject.propertyToGroupBy"];
NSUInteger sectionCount = [sorting count];
NSMutableArray *sections = [NSMutableArray arrayWithCapacity:sectionCount];
for (int i = 0; i < sectionCount; i++)
    [sections addObject:[NSMutableArray array]];

[values enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
    // Figure out the section for this object
    NSUInteger section = [sorting indexOfObject:obj.propertyToGroupBy];
    [[sections objectAtIndex:section] addObject:obj];
}];

// sections will contain as many sections as there were unique values
// each of those values is an array containing values that matched the criteria

这可能会被优化,但从我的头脑中,似乎符合要求。

编辑:再次回答问题之后,propertyToGroupBy必须规范化该值,即删除日期的时间成分,因为分组是通过唯一值完成的(即比较基于on isEqual:)