Un NSFetchedResultsController con la fecha como sectionNameKeyPath

Desarrollo una aplicación que utiliza datos básicos. En una UITableView, quiero mostrar una lista de mis entidades, ordenadas por la fecha guardada de los objetos. Cuando hago esto:

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

Obtengo una nueva sección para cada objeto porque este código agrupa las fechas según los segundos, también. Pero quiero una lista de los objetos, agrupados por fecha, pero solo de acuerdo con el día, mes y año. ¿Es posible y cómo?

¡¡Muchas gracias por su ayuda!! 😉

Esto debería hacer el truco para ti:

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

[EDITAR]

Jus vio tu comentario y para lo que estás tratando de lograr, puedes crear un atributo NSDate transitorio (no persistente) que está formateado de forma similar al código anterior (es decir, sin H: mm: ss ZZZZ) y usar ese atributo como su valor de sectionNameKeyPath .

Así que en pocas palabras para un objeto foo , con fooDate y fooDateTransient , usted:

  1. Obtenga su atributo foo.fooDate

  2. Transfórmalo usando el código anterior (o similar) y asigna el resultado de foo.fooDateTransient a foo.fooDateTransient

  3. Utilice fooDateTransient como su sectionNameKeyPath al crear el objeto fetchedResultsController .

PD: ¡No lo he probado yo mismo, pero debería valer la pena intentarlo!

Buena suerte, Rog

Consulte: http://developer.apple.com/library/ios/#samplecode/DateSectionTitles/Introduction/Intro.html#//apple_ref/doc/uid/DTS40009939

Funciona con mes y año, pero es bastante fácil hacerlo funcionar día, mes y año.

La siguiente es una solución de Swift 3 para ordenar por fecha, pero tienen títulos de sección correspondientes a días individuales.

  1. Agregue una propiedad transitoria llamada daySectionIdentifier a su entidad en Core Data.
  2. NSManagedObject su subclase NSManagedObject . Elimine la propiedad para daySectionIdentifier que se puede generar en Entity+CoreDataProperties.swift .
  3. Para el archivo Entity+CoreDataClass.swift , agregue el siguiente getter para 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. En su implementación UITableViewController , agregue el siguiente método:

     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. Al construir su NSFetchedResultsController , llame al inicializador con "daySectionIdentifier" como el parámetro sectionNameKeyPath .
  6. Establezca el NSFetchedResultsController de clasificación de NSFetchedResultsController el antiguo atributo "date" simple de su entidad. Es importante destacar que el orden de clasificación basado en "date" será coherente con el orden de clasificación basado en el identificador de sección que acabamos de construir.

Ahora debe tener su vista de tabla agrupada en secciones por día (p. Ej., “6 de febrero de 2017”) y ordenada por fecha detallada.

Creo que esto sería mejor.

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

Utilicé @ BoltClock’s a Unicorn y @ Rog’s’swser cuando tuve el mismo problema. Simplemente agregué un título transitorio de sección NSString * a mi objeto administrado, usé @ “sectionTitle” como sectionNameKeyPath y creé un getter personalizado como este:

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