2010-12-11 14 views
22

Desarrollo una aplicación que utiliza Core Data. En una UITableView, quiero mostrar una lista de mis entidades, ordenadas por la fecha guardada de los objetos. Cuando hago esto:A NSFetchedResultsController con fecha como sectionNameKeyPath

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

recibo para cada objeto una nueva sección porque los grupos de este Código las fechas de acuerdo con 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 !! ;)

Respuesta

41

Esto debe hacer el truco para usted:

- (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 vio su comentario y por lo que está tratando de lograr, se puede crear un atributo transitoria NSDate (no persistente) que está formateado de forma similar al código anterior (es decir, sin H: mm: ss ZZZZ) y usa ese atributo como su valor sectionNameKeyPath.

Así, en pocas palabras para un objeto foo, con fooDate y fooDateTransient atributos, lo haría:

  1. Obtenga su atributo foo.fooDate

  2. transformarlo utilizando el código anterior (o similar) y asignar el resultado NSDate a foo.fooDateTransient

  3. Usa fooDateTransient como sectionNameKeyPath al crear el objeto fetchedResultsController.

PD: ¡No he probado esto por mí mismo, pero debería valer la pena intentarlo!

Buena suerte, Rog

+0

Gracias, pero esa es la manera, cómo mostrar el título de las secciones. Pero no agrupa dos objetos con una misma fecha. Todavía hay una sección para cada objeto. –

+0

Bastante bien, he editado mi respuesta para sugerir una forma alternativa de probar. – Rog

+0

Muchas gracias Rog! Esto funciona. ¡Gracias! ;) –

0

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; 
} 
+0

Estuve de acuerdo con usted al principio, pero después de probar esto me di cuenta de que esto se ejecuta a través de todos los lotes en mi búsqueda y es REALMENTE lento en un gran conjunto de datos. Es un poco más rápido usar la solución de @Rog. –

-1

que utilizan @ BoltClock es un unicornio y @ anwser de Rog al tener el mismo problema. Simplemente añade un transitorio NSString * sectionTitle a mi objeto administrado, que se utiliza @ "sectionTitle" como sectionNameKeyPath y creó un captador de encargo de este modo:

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

Nunca use 'dateByAddingTimeInterval' para calcular las fechas. ¿Has considerado lo que sucedería en un año bisiesto? –

+0

Sí, este es solo un ejemplo básico para darle la idea –

+1

Dar código de ejemplo con código incorrecto siempre es una mala idea. En su lugar, todo se podría haber hecho con un NSDateFormatter simple que tenga la opción doRelativeDateFormatting establecida en SÍ. – Gargoyle

1

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

  1. Agregue una propiedad transitoria llamada daySectionIdentifier a su entidad en Core Data.
  2. Regenerar su subclase NSManagedObject. Elimine la propiedad para daySectionIdentifier que se puede generar en Entity+CoreDataProperties.swift.
  3. Para el archivo Entity+CoreDataClass.swift, añada el siguiente captador de 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 aplicación UITableViewController, añadir 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. Cuando la construcción de su NSFetchedResultsController, llamar a la inicialización con "daySectionIdentifier" como el parámetro sectionNameKeyPath.
  6. Establezca el descriptor de ordenación NSFetchedResultsController en el antiguo atributo "date" 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 (por ejemplo, "6 de feb, 2017") y ordenada por fecha de grano fino.

Cuestiones relacionadas