Выборка из базовых данных, отсортированных по форматированной дате - PullRequest
0 голосов
/ 16 ноября 2010

У меня проблемы с получением результатов из базовых данных, отсортированных по дате.

У меня есть таблица БД, которая содержит футбольные матчи. Каждый матч имеет homeTeam, awayTeam и kickoffTime. KickoffTime - это NSDate, в котором хранятся дата и время начала матча.

Я хочу отобразить результаты запроса в TableView, разделенном на разделы по дате начала. С датой в качестве заголовка раздела.

Это немного сложнее, чем может показаться на первый взгляд. Из-за различий в часовых поясах матч, начинающийся с одной даты в одной части мира, фактически начинается с другой даты в другой части мира. Поэтому я не могу просто проигнорировать время и сохранить даты начала в другом столбце.

То, что я пытаюсь сделать, создать пользовательский метод доступа, который возвращает отформатированную дату в любом часовом поясе, в котором находится пользователь, а затем использовать это для сортировки и разделения результатов. Вот мой код в Match.h:

@dynamic kickoffTime;
@dynamic formattedKickoffTime;
@dynamic dateFormatter;

- (NSString *)formattedKickoffTime
{
    [self willAccessValueForKey:@"kickoffTime"];

    // Set the date formatter to the format we want to display the date
    [dateFormatter setDateFormat:@"ccc, d MMM"];

    // Format the date
    NSString *myFormattedKickoffTime = [dateFormatter stringFromDate:[self kickoffTime]];

    [self didAccessValueForKey:@"kickoffTime"];

    // return the formatted date
    return myFormattedKickoffTime;
}

- (NSDateFormatter *)dateFormatter 
{   
    if (dateFormatter == nil) 
    {
        dateFormatter = [[NSDateFormatter alloc] init];
    }
    return dateFormatter;
}

@end

Однако, когда я пытаюсь получить и отсортировать данные следующим образом:

NSSortDescriptor *kickoffDescriptor = [[NSSortDescriptor alloc] initWithKey:@"formattedKickoffTime" ascending:YES];
...
NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:appDelegate.managedObjectContext sectionNameKeyPath:@"formattedKickoffTime" cacheName:nil];

Я получаю следующее сообщение об ошибке:

*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'keypath formattedKickoffTime not found in entity <NSSQLEntity Match id=1>'

Кто-нибудь может дать совет, пожалуйста?

1 Ответ

0 голосов
/ 17 ноября 2010

Итак, я нашел способ сделать это. Прежде всего я сохраняю все даты и расчеты в модели в GMT. Я добавляю пользовательский метод доступа (kickoffDate) в свою сущность Match, которая получает kickoffTime, устанавливает время 00:00:00 и возвращает его. Одна вещь, которую я должен был сделать, это было неочевидно, это установить timeZone даты, возвращаемой пользовательским средством доступа к GMT, иначе это было установлено на системную timeZone пользователя.

Поскольку все даты, возвращаемые моделью, указаны в GMT, все, похоже, работает, как и должно, независимо от того, какой часовой пояс я установил в настройках iPhone. Я думаю, что Core Data достаточно умен, чтобы выполнить настройку timeZone до того, как он поместит совпадения в разделы.

Хотя у меня есть один вопрос, является ли [NSTimeZone timeZoneForSecondsFromGMT:0] лучшим способом получить 0 часовых поясов, под этим я подразумеваю часовой пояс, на который летнее время не влияет?

О, и мне нужно звонить [self willAccessValueForKey:@"kickoffTime"]; и [self didAccessValueForKey:@"kickoffTime"];? Я не очень понимаю, что они делают!

Вот код в Match.h:

...
@dynamic homeTeam;
@dynamic awayTeam;
@dynamic kickoffTime;

- (NSDate *)kickoffDate
{
    [self willAccessValueForKey:@"kickoffTime"];
    NSCalendar *cal = [NSCalendar currentCalendar];
    NSDateComponents *components = [cal components:(NSYearCalendarUnit|NSMonthCalendarUnit|NSDayCalendarUnit) fromDate:[self primitiveValueForKey:@"kickoffTime"]];
    [components setHour:0];
    [components setMinute:0];
    [components setSecond:0];
    [components setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]];

    [self didAccessValueForKey:@"kickoffTime"];
    return [cal dateFromComponents:components];
}

А затем мой код выборки включает следующую сортировку по kickoffTime, а sectionNameKeyPath устанавливается в kickoffDate:

NSSortDescriptor *kickoffDescriptor = [[NSSortDescriptor alloc] initWithKey:@"kickoffTime" ascending:YES];
...
NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:appDelegate.managedObjectContext sectionNameKeyPath:@"kickoffDate" cacheName:nil];
...