2009-08-25 12 views
10

la documentación para NSFetchedResultsControllerDelegate proporcionan el código de ejemplo¿Se ha roto el comportamiento NSFetchedResultsControllerDelegate 'ChangeUpdate'?

- (void)controller:(NSFetchedResultsController *)controller 
    didChangeObject:(id)anObject 
     atIndexPath:(NSIndexPath *)indexPath 
    forChangeType:(NSFetchedResultsChangeType)type 
     newIndexPath:(NSIndexPath *)newIndexPath { 

    UITableView *tableView = self.tableView; 

    switch(type) { 

     case NSFetchedResultsChangeInsert: 
      [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade]; 
      break; 

     case NSFetchedResultsChangeDelete: 
      [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade]; 
      break; 

     case NSFetchedResultsChangeUpdate: 
      [self configureCell:[tableView cellForRowAtIndexPath:indexPath] atIndexPath:indexPath]; 
      break; 

     case NSFetchedResultsChangeMove: 
      [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade]; 
      [tableView reloadSections:[NSIndexSet indexSetWithIndex:newIndexPath.section] withRowAnimation:UITableViewRowAnimationFade]; 
      break; 

    } 

} 

Cuando creo un nuevo NSManagedObject, NSFetchedResultsChangeInsert incendios (grandes!). Cuando cambio el valor de un atributo (utilizado para el título de la celda), se activa el NSFetchedResultsChangeUpdate. Desafortunadamente, el nuevo título no se muestra automáticamente a menos que vuelva a cargar la tabla, sección o fila. De hecho, si el nuevo nombre hace que el conjunto de resultados se ordene de manera diferente, entonces se activa NSFetchedResultsChangeMove y todo está bien, ya que el código provisto vuelve a cargar toda la sección.

UITableView tiene un método reloadRowsAtIndexPaths: withRowAnimation así que intentaron usar este bajo el bloque de código NSFetchedResultsChangeUpdate. Se trabaja de hecho ... pero la documentación para este método específico leer como si yo no lo necesito (nótese la última línea):

volver a cargar una fila hace que la vista mesa para preguntar su fuente de datos para una nueva celda para esa fila. La tabla anima esa nueva celda en la que anima la fila anterior. Llame a este método si desea alertar al usuario de que el valor de una celda está cambiando. Si, no obstante, notificar al usuario no es importante, es decir, solo desea cambiar el valor que muestra una celda ; puede obtener la celda para una fila particular y establecer su nuevo valor.

Y sí, si me conecto lo que está sucediendo, cuando

[self configureCell:[tableView cellForRowAtIndexPath:indexPath] atIndexPath:indexPath]; 

se invoca en una NSFetchedResultsChangeUpdate, es capaz de recuperar el último valor 'nombre' y ponerlo en textLabel de la célula . El nombre simplemente no está renderizando en la celda a menos que lo vuelva a cargar. Incluso si simplemente hago clic en la celda, aparece el nombre. Tenga en cuenta que para volver a crear este comportamiento, debe crear un nuevo objeto administrado y luego darle un nombre que haga que clasifique FIRST en NSFetchedResultsController. De esta forma, NSFetchedResultsChangeMove no se activa (lo que funciona, ya que vuelve a cargar la sección).

¿Falta algo o me gusta? La 'discusión' de reloadRowsAtIndexPaths me lleva a pensar que debería ser capaz de simplemente configurar la etiqueta de texto de la celda sin volver a cargar la fila, la sección o la tabla.

+0

Esto debería ser wo rking. Estoy haciendo lo mismo. Para cambios en los atributos, cuando se llama a save: las notificaciones de MOC se apagan. NSFetchedResultsController ve el cambio y llama a mi método configureCell: atIndexPath. Ahí agarré los valores y llené la celda, y la celda se actualiza de inmediato. Publica tu código de configureCell. –

Respuesta

3

Debe llamar al [cell setNeedsLayout] y/o [cell setNeedsDisplay] para que la célula se actualice, dependiendo de la implementación de su celular.

Si compone la celda de las subvistas como solemos hacer, confíe en - layoutSubviews, por lo que debe llamar al [cell setNeedsLayout].

Si dibuja la celda directamente con – drawRect:, debe llamar al [cell setNeedsDisplay].

Si usa composición y dibujo, debe llamar a ambos.

1

Si bien es cierto que no necesita volver a cargar la celda para que los cambios tengan lugar, debe recordar que el iPhone almacena en caché el dibujo tanto como sea posible. Una vez que haya configurado su celda nuevamente, debe llamar a setNeedsDisplay en la celda para activar el redibujado.

+0

En este momento, ¿cuál es la mejor manera de obtener la celda que está en la pantalla? tableview: cellForRowAtIndexPath: crea una nueva celda, mientras que quiero obtener una referencia de la celda en la pantalla ... ¿verdad? –

+0

Normalmente, no es necesario, para cualquier celda que esté configurando, puede llamar a setNeedsDisplay. Si se trata de una nueva celda, no tiene un caché, por lo que no te preocupes, si estás reconfigurando, volverá a dibujar. Sin embargo, si realmente quiere saber qué pantallas son visibles, eche un vistazo a mi respuesta a: http://stackoverflow.com/questions/996515/getting-visible-cell-from-uitableview-pagingenabled/1566432#1566432 –

1

Aunque no ha sido explícitamente, has hecho tiene que asegurarse de que incluye los métodos de delegado para controllerWillChangeContent: y controllerDidChangeContent:

- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller { 
    [self.tableView beginUpdates]; 
} 

y

- (void)controllerDidChangeContent:(BSFetchedResultsController *)controller { 
    @try { 
     [self.tableView endUpdates]; 
    } 
    @catch (NSException * e) { 
     NSLog(@"caught exception: %@: %@", [e name], [e description]); 
    } 
    @finally { } 
} 

El NSFRC puede disparar off multiple controller: didChangeObject: atIndexPath: forChangeType: newIndexPath: métodos durante cualquier cambio, por lo que no espere que la fila de la tabla se actualice inmediatamente después de cada uno de ellos. Solo se actualizarán después de llamar a endUpdates en la mesa.

0

Llamar a la interfaz de usuario de la actualización de la lógica en hilo principal resuelto mi problema (ambos [cell setNeedsLayout] & [cell setNeedsDisplay] no funciona para mí):

... 
case NSFetchedResultsChangeUpdate: 
    dispatch_async(dispatch_get_main_queue(), { 
     [self configureCell:[tableView cellForRowAtIndexPath:indexPath] atIndexPath:indexPath]; 
    }); 
    break; 
... 

Lo que es más (no sobre este tema, pero será útil), es mejor que elija utilizar newIndexPath si está disponible:

... 
case NSFetchedResultsChangeUpdate: 
    dispatch_async(dispatch_get_main_queue(), { 
     NSIndexPath * targetIndexPath = (newIndexPath ?: indexPath) 
     [self configureCell:[tableView cellForRowAtIndexPath:targetIndexPath] 
       atIndexPath:targetIndexPath]; 
    }); 
    break; 
... 
+1

aquellos los eventos ya están en el hilo principal, lo que está haciendo es derivar al próximo ciclo de eventos, aunque GCD no es 100% bueno en eso, realizar después de que el retraso sea más confiable. – malhal

+0

@malhal buen punto. – Kjuly

Cuestiones relacionadas