我的tableView中有三个部分:
Today
Upcoming
Past
当应用程序启动时,启动的视图控制器具有NSFetchedResultsController。如果我第一次删除应用程序并在模拟器中重新启动它,它运行得很好;但是,当日期发生变化时,意味着第二天,应用程序会给出以下错误:
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'";
}
指数各不相同。
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];
sortKey
不是短暂的。我不确定它是否应该。
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;
}
我按照Apple的示例代码创建了一个瞬态属性sectionIdentifier
和sortKey
,以便按以下顺序显示部分:
1. Today
2. Upcoming
3. Past
如果对象不适用于任何部分,则不会显示该部分。我正在使用modifiedDate
来确定对象所属的section
。
关于SO的大多数问题声称第一种排序应该是sectionIdentifier
,但这是一种短暂的属性。另外,Apple的示例不使用sectionIdentifier
作为第一种。有什么建议吗?
修改
这是我的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
我从sectionIdentifier
删除了(!tmp)以查看有帮助,但无效。 Core Data中没有数据更改。
- (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;
}
答案 0 :(得分:1)
您的主要问题似乎是触发更新过程以运行和修改您的数据存储内容。
当您更新sectionIdentifier
和sortKey
时,您可以存储计算它们的日期,并比较请求检查日期仍然有效的日期。这使您可以轻松地检查在收到触发器时是否需要进行任何更新,以告知您某些内容已发生更改并且您需要进行验证。
对于触发器,您需要考虑应用程序到达前台,重要时间更改以及应用程序打开时的更改日期。因此,您可以从应用程序委托(或观察激活)触发,并且您可以观察UIApplicationSignificantTimeChangeNotification
并且您可以配置计时器(当应用程序被激活时),该计时器倒计时到当天结束时(在应用程序转到后台)。
现在你有了触发器和动作。但是,当收到触发器时,您的视图控制器将不会始终存在,因此请考虑使用数据更新控制器来管理此过程。
答案 1 :(得分:1)
我很确定您的排序代码可以大大简化。但也许这是一个不同的问题。无论如何,目前尚不清楚,如果设置startDate
并且有太多变量使得算法非常复杂。你能尝试使用日期和部分标识符进行重构吗?部分标识符应以正确的方式排序 - 您可以添加逻辑以在其他位置显示某些自定义字符串。
这是你应该尝试的东西。消除if (!tmp)
检查 - 为了我的目的,我很幸运地修复了这个示例代码。
最后,目前尚不清楚如何在日期更改时更新FRC。确保您希望更改的数据按预期更新。