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
{
[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
{
[self willChangeValueForKey:@"startDate"];
[self setPrimitiveStartDate:newDate];
[self didChangeValueForKey:@"startDate"];
[self setPrimitiveSectionIdentifier:nil];
}
- (void)setSortKey:(NSNumber *)sortKey
{
[self willChangeValueForKey:@"sortKey"];
[self setPrimitiveSortKey:sortKey];
[self didChangeValueForKey:@"sortKey"];
[self setPrimitiveSortKey:nil];
}
#pragma mark - Key path dependencies
+ (NSSet *)keyPathsForValuesAffectingSectionIdentifier
{
return [NSSet setWithObject:@"sortKey"];
}
+ (NSSet *)keyPathsForValuesAffectingSortKey
{
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;
}