Основные данные: извлеченный объект с индексом x имеет имя раздела без порядка "xxxxxx". Объекты должны сортироваться по названию раздела
Я знаю, что я не первый, кто задал этот вопрос, но я действительно в тупике.
В основном у меня есть экран с двумя кнопками. Каждая кнопка загружает данные в таблицу ниже по дате. При первом загрузке первого представления таблицы (по умолчанию выбрана левая кнопка), все отображается нормально. Если я нажму на правую кнопку, и я получу пустой стол, и я получу ошибку
Приобретенный объект с индексом x имеет имя раздела вне порядка "XXXXXX. Объекты должны быть отсортированы по имени раздела.
Возвращаясь к левому экрану таблицы, данные исчезли. Оба табличных поля пусты.
В каждом представлении таблицы есть 2 раздела в зависимости от времени начала элемента. Если я исключаю разделы, данные отображаются в порядке. К сожалению, мне они нужны. Данные сортируются по двум разделам следующим образом:
@interface NSString(agendaSessionKeyPath)
@property (nonatomic, readonly) NSString *sessionSection;
@end
@implementation NSString(agendaSessionKeyPath)
- (NSString *)sessionSection
{
int timeValue = [[self stringByReplacingOccurrencesOfString:@":" withString:@""] intValue]; //turns 11:00 to 1100
if (timeValue < 1200)
return @"Morning";
else
return @"Afternoon";
}
Запрос на выборку
- (void)viewDidLoad
{
//other viewDidLoad stuff
[self fetchSessions];
}
который сортирует данные с левой и правой кнопки в зависимости от даты:
- (void)fetchSessions
{
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]];
[dateFormatter setDateFormat:@"yyyy-MM-dd"];
NSDate* date = nil;
if (selected == 0) //left button is selected
{
date = [dateFormatter dateFromString:@"2012-09-26"];
}
else if (selected == 1) //right button is selected
{
date = [dateFormatter dateFromString:@"2012-09-27"];
}
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"date == %@", date];
[self.fetchedResultsController.fetchRequest setPredicate:predicate];
NSError *error;
if (![[self fetchedResultsController] performFetch:&error]) {
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
}
}
извлеченный контроллер результатов
- (NSFetchedResultsController *)fetchedResultsController {
self.managedObjectContext = [[MATCDatabaseController sharedDatabaseController] managedObjectContext];
if (_fetchedResultsController != nil) {
return _fetchedResultsController;
}
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:@"Session"];
NSSortDescriptor *sort = [[NSSortDescriptor alloc]
initWithKey:@"title" ascending:YES];
NSSortDescriptor *timeSort = [NSSortDescriptor sortDescriptorWithKey:@"timeValue" ascending:YES];
[fetchRequest setSortDescriptors:@[timeSort, sort]];
[fetchRequest setFetchBatchSize:20];
NSFetchedResultsController *theFetchedResultsController =
[[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
managedObjectContext:self.managedObjectContext sectionNameKeyPath:@"startTime.sessionSection"
cacheName:nil];
self.fetchedResultsController = theFetchedResultsController;
[self.fetchedResultsController setDelegate:self];
return _fetchedResultsController;
}
любая помощь приветствуется!
Ответы
Ответ 1
Хорошо, я быстро заглянул.
Вы инициализируете FRC:
[[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
managedObjectContext:self.managedObjectContext
sectionNameKeyPath:@"startTime.sessionSection"
cacheName:nil];
который сообщает, что ваши заголовки разделов должны быть получены с помощью пути ключа startTime.sessionSection
.
Теперь для сортировки разделов будет использоваться первый дескриптор сортировки запроса на выборку, который присваивается FRC. Сначала дескриптор сортировки, который вы предоставляете, - это timeValue
, который кажется неправильным.
Ваш первый дескриптор сортировки должен указать сортировку для заголовков разделов. Измените это, и вам может быть хорошо.
ИЗМЕНИТЬ
Спасибо, ребята, за информацию. Я все еще немного потерял. Ты имел ввиду что я должен добавить дескриптор сортировки в startTime.sessionSection раньше присвоив его разделуNameKeyPath? Я пробовал, но все равно не повезло. timeValue и startTime.sessionSection связаны между собой. Может ли это так? - pigeonfactory
Вы должны убедиться, что самый первый дескриптор сортировки будет правильно сортировать ваши данные на основе раздела. В вашем случае времена преобразуются в слова. Ваш первоначальный дескриптор сортировки выполняется по времени, и когда данные сортируются в зависимости от времени, разделы не сортируются должным образом, что вызывает вашу ошибку.
Самый первый дескриптор сортировки должен удовлетворять данным раздела. Итак, изначально, я бы попытался...
[fetchRequest setSortDescriptors:@[
[NSSortDescriptor sortDescriptorWithKey:@"startTime.sessionSection"
ascending:NO],
[NSSortDescriptor sortDescriptorWithKey:@"timeValue"
ascending:YES],
[NSSortDescriptor sortDescriptorWithKey:@"title"
ascending:YES] ];
Примечание. Если у вас много и много данных, вы можете обнаружить, что ваш секционный механизм замедляется. Если это произойдет, вы можете захотеть добавить данные этого раздела в свою базу данных.
Ответ 2
У меня тоже есть аналогичная проблема, возможно, кто-то найдет ее полезной.
Я взял финансовые транзакции из БД и разделил их на месяц.
DB имеет свойство trDate - дату транзакции. Но trMonth является временным свойством, например:
- (NSString*)trMonth {
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:@"LLLL"];
[dateFormatter setLocale:[NSLocale currentLocale]];
return [dateFormatter stringFromDate:trDate];
}
Он использовался в FetchResultsController следующим образом:
...
NSSortDescriptor *sortDate = [[NSSortDescriptor alloc] initWithKey:@"trDate" ascending:YES];
[fetchRequest setSortDescriptors:@[sortDate]];
NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:@"trMonth" cacheName:nil];
...
Что хорошо сработало в производстве, но как только приложение начало рушиться, и после обнаружения корневой проблемы я выяснил, что две транзакции для (например) в июле: июль 2014 года и июль 2015 года. Это была краш-точка как trDate сортированная скважина Июль 2014 г. < Июль 2015 года, но мой метод рассматривал их как один месяц. В качестве имен разделов использовалось не только название месяца, но и год:
- (NSString*)trMonthYear {
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:@"LLLL yyyy"]; // added year also
[dateFormatter setLocale:[NSLocale currentLocale]];
return [dateFormatter stringFromDate:trDate];
}