NSFetchedResultsController с датой в виде sectionNameKeyPath


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

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

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

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

5 22

5 ответов:

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

- (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 вы бы:

  1. Получите ваш foo.fooDate атрибут

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

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

PS: Я не проверял это сам, но стоит попробовать!

Удачи, Rog

Проверьте: http://developer.apple.com/library/ios/#samplecode/DateSectionTitles/Introduction/Intro.html#//apple_ref/doc/uid/DTS40009939

Он работает с месяцем и годом, но довольно легко заставить его работать с днем, месяцем и годом.

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

  1. добавьте переходное свойство daySectionIdentifier к вашей сущности в основных данных.
  2. Регенерируйте свой подкласс NSManagedObject. Удалите свойство для daySectionIdentifier, которое может быть сгенерировано в Entity+CoreDataProperties.swift.
  3. В файл Entity+CoreDataClass.swift добавьте следующий геттер для daySectionIdentifier:

    // Transient property for grouping a table into sections based
    // on day of entity's 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
    }
    
  4. В вашей реализации 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
    }
    
  5. при построении вашего NSFetchedResultsController, вызовите инициализатор с "daySectionIdentifier" в качестве параметра sectionNameKeyPath.
  6. установите дескриптор сортировки вашего NSFetchedResultsController в обычный старый атрибут вашей сущности "date". Важно отметить, что порядок сортировки, основанный на "date", будет соответствовать порядку сортировки, основанному на идентификаторе раздела, который мы только что построили.

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

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

- (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;
}

Я использовал единорога @BoltClock и anwser @Rog, когда у меня была та же проблема. Просто добавил временный 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;
}