NSFetchedResultsController:重新排序部分

Posted

技术标签:

【中文标题】NSFetchedResultsController:重新排序部分【英文标题】:NSFetchedResultsController: ReOrder Sections 【发布时间】:2014-06-18 18:53:52 【问题描述】:

我正在按照 Apple 的示例来设置我的部分:

https://developer.apple.com/library/ios/samplecode/DateSectionTitles/Listings/DateSectionTitles_APLEvent_m.html

我的部分目前按以下顺序显示:

Section 0: "Upcoming"
Section 1: "Today"
Section 2: "Past"

我在NSManagedObject .m 文件中使用的代码:

#pragma mark - Transient properties

- (NSString *)sectionIdentifier

    // Create and cache the section identifier on demand.

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

    if (!tmp)
    
        NSDate *dateToCompare = [self getUTCFormateDate:[self startDate]];
        NSLog(@"********Date To Compare****** %@", dateToCompare);

        NSCalendar* calendar = [NSCalendar currentCalendar];
        NSDate* now = [NSDate date];
        NSDateFormatter *format = [[NSDateFormatter alloc] init];
        format.dateFormat = @"dd-MM-yyyy";
        NSString *stringDate = [format stringFromDate:now];
        NSDate *todaysDate = [format dateFromString:stringDate];

        NSInteger differenceInDays =
        [calendar ordinalityOfUnit:NSDayCalendarUnit inUnit:NSEraCalendarUnit forDate:dateToCompare] -
        [calendar ordinalityOfUnit:NSDayCalendarUnit inUnit:NSEraCalendarUnit forDate:todaysDate];

        NSString *sectionString;

        if (differenceInDays == 0)
        
            sectionString = kSectionIDToday;
        
        else if (differenceInDays < 0)
        
            sectionString = kSectionIDPast;
        
        else if (differenceInDays > 0)
        
            sectionString = kSectionIDUpcoming;
         

        tmp = sectionString;
        [self setPrimitiveSectionIdentifier:tmp];
    

    return tmp;


-(NSDate *)getUTCFormateDate:(NSDate *)localDate

    NSDateFormatter *dateFormatter;
    if (!dateFormatter)
    
        dateFormatter = [[NSDateFormatter alloc] init];
    
    NSTimeZone *timeZone = [NSTimeZone timeZoneWithName:@"UTC"];
    [dateFormatter setTimeZone:timeZone];
    [dateFormatter setDateFormat:@"yyyy-MM-dd"];
    NSString *dateString = [dateFormatter stringFromDate:localDate];
    NSDate *dateFromString = [[NSDate alloc] init];
    dateFromString = [dateFormatter dateFromString:dateString];
    return dateFromString;


#pragma mark - Time stamp setter

- (void)setStartDate:(NSDate *)newDate

    // If the time stamp changes, the section identifier become invalid.
    [self willChangeValueForKey:@"startDate"];
    [self setPrimitiveStartDate:newDate];
    [self didChangeValueForKey:@"startDate"];

    [self setPrimitiveSectionIdentifier:nil];



#pragma mark - Key path dependencies

+ (NSSet *)keyPathsForValuesAffectingSectionIdentifier

    // If the value of timeStamp changes, the section identifier may change as well.
    return [NSSet setWithObject:@"startDate"];

在我的 tableViewController 中,我将 NSFetchedResults 设置如下:

- (NSFetchedResultsController *)fetchedResultsController

    if(_fetchedResultsController!=nil)
    
        return  _fetchedResultsController;
    

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

    NSSortDescriptor *firstSort = [[NSSortDescriptor alloc] initWithKey:@"startDate"
                                                              ascending:NO];


    NSArray *sortDescriptors = [[NSArray alloc]initWithObjects:firstSort,nil];

    [fetchRequest setSortDescriptors:sortDescriptors];

    self.fetchedResultsController = [[NSFetchedResultsController alloc]initWithFetchRequest:fetchRequest
                                                                       managedObjectContext:self.managedObjectContext
                                                                         sectionNameKeyPath:@"sectionIdentifier"
                                                                                  cacheName:nil];
    self.fetchedResultsController.delegate = self;
    return self.fetchedResultsController;

问题 1:如何让这些部分按以下顺序显示:

Section 0: Today
Section 1: Upcoming
Section 2: Past

问题 2:在每个部分中,如何根据每个对象中名为 "modified" 的属性对行进行排序?

【问题讨论】:

【参考方案1】:

节和行排序都 100% 取决于排序描述符。您希望您的第一个排序描述符将所有内容排序到正确的部分,然后您的后续排序描述符将对部分中的行进行排序。

例如,如果您想要基于“组”的三个部分,然后您想要在组内按名称排序的行,您可以将排序描述符添加为:

NSArray *descriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"group" ascending:YES], [NSSortDescriptor sortDescriptorWithKey:@"name" ascending:YES]];
[fetchRequest setSortDescriptors:descriptors];

NSFetchedResultsController 的分区键也需要与您的第一个 NSSortDescriptor 匹配。

【讨论】:

谢谢。所有对象都根据名为startDate 的属性进行排序。我如何让Today 的部分出现在Upcoming 之前。我是否需要创建另一个名为 sortKey 的瞬态属性并首先根据它进行排序? 是的,创建一个新键以在顶部进行排序,以将所有内容放入适当的部分。 NSSortDescriptor 实例需要非瞬态属性,因此您需要考虑设计的那部分... 我终于决定换个型号,加了一个sortKey。但现在我遇到了另一个错误:CoreData: error: (NSFetchedResultsController) The fetched object at index 3 has an out of order section name ' Past. Objects must be sorted by section name' 我做了一个重复错误的示例项目:github.com/KausiAhmed/FRC 您的排序需要从您的sectionIdentifier 开始,然后您可以按其他任何内容进行排序。但第一个NSSortDescriptor 必须与sectionNameKeyPath 匹配。 感谢您查看代码!我一直在关注 Apple 的代码,它具有 sectionIdentifier 作为 transient 属性,并且它不基于 sectionNameKeyPath 排序:developer.apple.com/library/ios/samplecode/DateSectionTitles/… 我应该将其更改为非瞬态属性吗?我在想也许为每个部分做一个单独的 FRC?

以上是关于NSFetchedResultsController:重新排序部分的主要内容,如果未能解决你的问题,请参考以下文章

在 Core Data 应用程序中调用 performFetch 后,是不是需要手动更新表视图?