Подтвердить что ты не робот

NSFetchedResultsController с датой как sectionNameKeyPath

Я разрабатываю приложение, которое использует Core Data. В одном UITableView я хочу отобразить список моих объектов, отсортированных по сохраненной дате объектов. Когда я это сделаю:

fetchedResultsController = [[NSFetchedResultsController alloc]
                            initWithFetchRequest:fetchRequest
                            managedObjectContext:managedObjectContext
                              sectionNameKeyPath:@"date"
                                       cacheName:nil];

Я получаю для каждого объекта новый раздел, потому что этот код также группирует даты в соответствии с секундами. Но мне нужен список объектов, сгруппированных по дате, но только по дням, месяцам и годам. Это возможно и как?

Большое спасибо за вашу помощь!!;)

4b9b3361

Ответ 1

Это должно сделать трюк для вас:

- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
  NSString *rawDateStr = [[[self.fetchedResultsController sections] objectAtIndex:section] name];
  // Convert rawDateStr string to NSDate...
  NSDateFormatter *formatter = [[[NSDateFormatter alloc] init] autorelease];
  [formatter setDateFormat:@"yyyy-MM-dd HH:mm:ss ZZ"];
  NSDate *date = [formatter dateFromString:rawDateStr];

  // Convert NSDate to format we want...
  [formatter setDateFormat:@"d MMMM yyyy"];
  NSString *formattedDateStr = [formatter stringFromDate:date];
  return formattedDateStr;  
}

[EDIT]

Jus увидел ваш комментарий и то, что вы пытаетесь достичь, вы можете создать переходный NSDate атрибут (не постоянный), который отформатирован аналогично приведенному выше коду (т.е. без H: mm: ss ZZZZ) и использовать этот атрибут как ваше значение sectionNameKeyPath.

Итак, в двух словах для объекта foo, с атрибутами fooDate и fooDateTransient, вы должны:

  • Получите атрибут foo.fooDate

  • Преобразуйте его с помощью кода выше (или аналогичного) и назначьте результат NSDate foo.fooDateTransient

  • Используйте fooDateTransient как ваш sectionNameKeyPath при создании объекта fetchedResultsController.

PS: Я не тестировал это сам, но должен быть достоин!

Удачи, Рог

Ответ 3

Ниже приведено решение Swift 3 для сортировки по дате, но есть заголовки разделов, соответствующие отдельным дням.

  • Добавить свойство переходного процесса, называемое daySectionIdentifier, вашей сущности в Core Data.
  • Восстановите свой подкласс NSManagedObject. Удалите свойство для daySectionIdentifier, которое может быть сгенерировано в Entity+CoreDataProperties.swift.
  • В файл Entity+CoreDataClass.swift добавьте следующий getter для daySectionIdentifier:

    // Transient property for grouping a table into sections based
    // on day of entity date. Allows an NSFetchedResultsController
    // to sort by date, but also display the day as the section title.
    //   - Constructs a string of format "YYYYMMDD", where YYYY is the year,
    //     MM is the month, and DD is the day (all integers).
    
    public var daySectionIdentifier: String? {
        let currentCalendar = Calendar.current
        self.willAccessValue(forKey: "daySectionIdentifier")
        var sectionIdentifier = ""
        if let date = self.date as? Date {
            let day = currentCalendar.component(.day, from: date)
            let month = currentCalendar.component(.month, from: date)
            let year = currentCalendar.component(.year, from: date)
    
            // Construct integer from year, month, day. Convert to string.
            sectionIdentifier = "\(year * 10000 + month * 100 + day)"
        }
        self.didAccessValue(forKey: "daySectionIdentifier")
    
        return sectionIdentfier
    }
    
  • В вашей реализации UITableViewController добавьте следующий метод:

    override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
        var sectionTitle: String?
        if let sectionIdentifier = fetchedResultsController.sections?[section].name {
            if let numericSection = Int(sectionIdentifier) {
                // Parse the numericSection into its year/month/day components.
                let year = numericSection / 10000
                let month = (numericSection / 100) % 100
                let day = numericSection % 100
    
                // Reconstruct the date from these components.
                var components = DateComponents()
                components.calendar = Calendar.current
                components.day = day
                components.month = month
                components.year = year
    
                // Set the section title with this date
                if let date = components.date {
                    sectionTitle = DateFormatter.localizedString(from: date, dateStyle: .medium, timeStyle: .none)
                }
            }
        }
    
        return sectionTitle
    }
    
  • При построении NSFetchedResultsController вызовите инициализатор с "daySectionIdentifier" как параметр sectionNameKeyPath.
  • Установите дескриптор сортировки NSFetchedResultsController в свой обычный простой атрибут "date". Важно отметить, что порядок сортировки, основанный на "date", будет соответствовать порядку сортировки на основе только что построенного идентификатора раздела.

Теперь вы должны иметь сводку таблицы, сгруппированную по секциям в день (например, "6 февраля 2017 года" ) и отсортированную по мелкозернистой дате.

Ответ 4

Я думаю, это было бы лучше.

- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {

    // Replace DataClassObject with whatever object your using
    DataClassObject *tempObject = [[sectionInfo objects] objectAtIndex:0];

    NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
    [formatter setDateFormat:@"d MMMM yyyy"];
    NSString *formattedDateStr = [formatter stringFromDate:tempObject.date];
    [dateFormatter release]

    return formattedDateStr;
}

Ответ 5

Я использовал @BoltClock a Unicorn и @Rog anwser, когда имел ту же проблему. Просто добавленный переходный NSString * sectionTitle к моему управляемому объекту, использовал @ "sectionTitle" как sectionNameKeyPath и создал пользовательский геттер, например:

-(NSString *)sectionTitle
{
    NSDate *_now = [NSDate date];
    NSDate *_today = [_now dateByAddingTimeInterval: -86400.0];
    NSDate *_yesterday = [_now dateByAddingTimeInterval: -172800.0];
    NSDate *_thisWeek  = [_now dateByAddingTimeInterval: -604800.0];
    NSDate *_lastWeek  = [_now dateByAddingTimeInterval: -1209600.0];
    NSDate *_thisMonth = [_now dateByAddingTimeInterval: -2629743.0]; 
   // if better precision required use something more sophisticated for month...

   double today = [_today timeIntervalSince1970];
   double yesterday = [_yesterday timeIntervalSince1970]; 
   double thisWeek = [_thisWeek timeIntervalSince1970];
   double lastWeek = [_lastWeek timeIntervalSince1970]; 
   double thisMonth = [_thisMonth timeIntervalSince1970];

   [self willAccessValueForKey:@"timestamp"];
       double ts = [self.timestamp timeIntervalSince1970];
   [self didAccessValueForKey:@"timestamp"];

   NSString *title = @"";
   if(ts >= today) title = NSLocalizedString(@"TODAY",nil);
   else if (ts >= yesterday) title = NSLocalizedString(@"YESTERDAY",nil);
   else if (ts >= thisWeek) title = NSLocalizedString(@"THIS WEEK",nil);
   else if (ts >= lastWeek) title = NSLocalizedString(@"LAST WEEK",nil);
   else if (ts >= thisMonth) title = NSLocalizedString(@"THIS MONTH",nil);

   return title;
}