NSFetchedResultsController: an extracted object with index x has a section name out of order

I have three sections in my View table:

Today
Upcoming
Past  

When the application starts, there is an NSFetchedResultsController in the running view manager. If I delete the application and restart it in the simulator for the first time, it works fine; however, when the date changes, which means the day after, the application reports an error below:

2014-06-29 19:48:35.326 App[37398:4803] CoreData: error: (NSFetchedResultsController) The fetched object at index 4 has an out of order section name '  Upcoming. Objects must be sorted by section name'
2014-06-29 19:48:35.328 App[37398:4803] Unresolved error Error Domain=NSCocoaErrorDomain Code=134060 "The operation couldn’t be completed. (Cocoa error 134060.)" UserInfo=0xf990fc0 {reason=The fetched object at index 4 has an out of order section name '  Upcoming. Objects must be sorted by section name'}, {
    reason = "The fetched object at index 4 has an out of order section name '  Upcoming. Objects must be sorted by section name'";
}

The index is changing.

NSFetchedResultsConroller:

- (NSFetchedResultsController *)fetchedResultsController
{
    if(_fetchedResultsController!=nil)
    {
        return  _fetchedResultsController;
    }

    if (!self.objectManager)
    {
        self.objectManager = [self getObjectManager];
    }
    self.managedObjectContext = self.objectManager.managedObjectStore.mainQueueManagedObjectContext;
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"Meeting"
                                              inManagedObjectContext:self.managedObjectContext];
    [fetchRequest setEntity:entity];

sortKeyis not transitional. I'm not sure what it should be or not.

    NSSortDescriptor *firstSort = [[NSSortDescriptor alloc] initWithKey:@"sortKey"
                                                              ascending:YES];
    NSSortDescriptor *secondSort = [[NSSortDescriptor alloc] initWithKey:@"modifiedDate"
                                                               ascending:NO];


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

    [fetchRequest setSortDescriptors:sortDescriptors];


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

I followed the Apple sample code example and created a transient property sectionIdentifierand sortKeyto always display sections in the following order:

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

   1. Today
   2. Upcoming
   3. Past 

, . modifiedDate, , section .

SO , sectionIdentifier, . , Apple sectionIdentifier . ?

Edit

NSManagedObject.m:

@dynamic primitiveSectionIdentifier, primitiveSortKey, primitiveModifiedDate, primitiveStartDate;

#pragma mark - Transient properties

- (NSString *)sectionIdentifier
{
    // Create and cache the section identifier on demand.

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

    [self willAccessValueForKey:@"sortKey"];
    NSNumber *tempSort = [self primitiveSortKey];
    [self didAccessValueForKey:@"sortKey"];


    if (!tmp)
    {

        NSDate *dateToCompare = [self getcurrentTime:[self startDate]];
        NSCalendar* calendar = [NSCalendar currentCalendar];
        NSDate* now = [self getcurrentTime:[NSDate date]];
        NSDateFormatter *format = [[NSDateFormatter alloc] init];
        format.dateFormat = @"dd-MM-yyyy";
        format.timeZone = [NSTimeZone timeZoneForSecondsFromGMT:0];
        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];
        NSLog(@"differenceInDays %i", differenceInDays);

        NSString *sectionString;
        NSNumber *sortNumber;

        if (differenceInDays == 0)
        {
            sectionString = kSectionIDToday;
            sortNumber = [NSNumber numberWithInt:0];

        }
        else if (differenceInDays < 0)
        {
            sectionString = kSectionIDPast;
            sortNumber = [NSNumber numberWithInt:2];


        }
        else if (differenceInDays > 0)
        {
            sectionString = kSectionIDUpcoming;
            sortNumber = [NSNumber numberWithInt:1];
        }

        tmp = sectionString;
        tempSort = sortNumber;
        [self setPrimitiveSectionIdentifier:tmp];
        [self setPrimitiveSortKey:tempSort];    
    }

    return tmp;
}

-(NSDate *)getcurrentTime:(NSDate*)date
{
    NSDate *sourceDate = date;
    NSTimeZone* sourceTimeZone = [NSTimeZone timeZoneWithAbbreviation:@"GMT"];
    NSTimeZone* destinationTimeZone = [NSTimeZone systemTimeZone];

    NSInteger sourceGMTOffset = [sourceTimeZone secondsFromGMTForDate:sourceDate];
    NSInteger destinationGMTOffset = [destinationTimeZone secondsFromGMTForDate:sourceDate];
    NSTimeInterval interval = destinationGMTOffset - sourceGMTOffset;

    NSDate* currentDate = [[NSDate alloc] initWithTimeInterval:interval sinceDate:sourceDate];
    return currentDate;
}


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

- (void)setSortKey:(NSNumber *)sortKey
{
    // If the time stamp changes, the section identifier become invalid.
    [self willChangeValueForKey:@"sortKey"];
    [self setPrimitiveSortKey:sortKey];
    [self didChangeValueForKey:@"sortKey"];

    [self setPrimitiveSortKey:nil];
}


#pragma mark - Key path dependencies

+ (NSSet *)keyPathsForValuesAffectingSectionIdentifier
{
    // If the value of timeStamp changes, the section identifier may change as well.
    return [NSSet setWithObject:@"sortKey"];
}

+ (NSSet *)keyPathsForValuesAffectingSortKey
{
    // If the value of timeStamp changes, the section identifier may change as well.
    return [NSSet setWithObject:@"modifiedDate"];
}

2

. , sortKey Core Data ( , .sqllite). , , , . CoreData, sortKey . , sortKey , , .

3

(! tmp) sectionIdentifier, , , . .

- (NSString *)sectionIdentifier
{
    [self willAccessValueForKey:@"sectionIdentifier"];
    NSString *tmp = [self primitiveSectionIdentifier];
    [self didAccessValueForKey:@"sectionIdentifier"];

    [self willAccessValueForKey:@"sortKey"];
    NSNumber *tempSort = [self primitiveSortKey];
    [self didAccessValueForKey:@"sortKey"];

    NSDate *dateToCompare = [self getcurrentTime:[self startDate]];
    NSCalendar* calendar = [NSCalendar currentCalendar];
    NSDate* now = [self getcurrentTime:[NSDate date]];
    NSDateFormatter *format = [[NSDateFormatter alloc] init];
    format.dateFormat = @"dd-MM-yyyy";
    format.timeZone = [NSTimeZone timeZoneForSecondsFromGMT:0];
    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;
    NSInteger sortNumber = 0;

    if (differenceInDays == 0)
    {
        sectionString = kSectionIDToday;
        sortNumber = 0;
    }
    else if (differenceInDays < 0)
    {
        sectionString = kSectionIDPast;
        sortNumber = 2;
    }
    else if (differenceInDays > 0)
    {
        sectionString = kSectionIDUpcoming;
        sortNumber = 1;
    }

    if (sortNumber != [tempSort integerValue])
    {
        tmp = sectionString;
        tempSort = [NSNumber numberWithInt:sortNumber];
        [self setPrimitiveSectionIdentifier:tmp];
        [self setPrimitiveSortKey:tempSort];
    }    
    return tmp;
}
+1
2

, . , , . , , startDate , . ? - .

. if (!tmp) - .

, , FRC . , , , .

+1

.

sectionIdentifier sortKey, , , , , . , - , , , - , .

, , , . , ( ), UIApplicationSignificantTimeChangeNotification, ( ), ( , ).

, . , .

+1

All Articles