NSFetchedResultsController: изменить порядок разделов

#uitableview #core-data #ios7 #nsfetchedresultscontroller

#uitableview #ядро-данные #ios7 #NSFetchedResultsController

Вопрос:

Я следую примеру от 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 .

Комментарии:

1. Спасибо. Все объекты сортируются на основе вызываемого атрибута startDate . Как бы я заставил Today раздел появляться раньше Upcoming . Нужно ли мне сначала создать другое вызываемое временное свойство sortKey и отсортировать его на основе этого?

2. да, создайте новый ключ для сортировки вверху, чтобы поместить все в соответствующие разделы. NSSortDescriptor экземплярам требуются нестационарные свойства, поэтому вам нужно подумать об этой части вашего дизайна…

3. Я, наконец, решил изменить модель и добавил 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

4. Ваша сортировка должна начинаться с вашей sectionIdentifier , а затем вы можете сортировать по чему-либо еще. Но первый NSSortDescriptor должен соответствовать sectionNameKeyPath .

5. Спасибо, что взглянули на код! Я следил за кодом Apple, и он имеет sectionIdentifier transient свойство и не сортируется на основе sectionNameKeyPath : developer.apple.com/library/ios/samplecode/DateSectionTitles/… Должен ли я изменить его на свойство non-transient? Я думал, возможно, сделать отдельный FRC для каждого раздела?