2009-11-11 21 views
17

Estoy tratando de cambiar la clasificación en un NSFetchController sobre la marcha, por algún tipo de control segmentado. Para ordenar A-> Z Z-> A tipo cosa.Cambiar la ordenación en un NSFetchedResultsController sobre la marcha

¿Qué tengo que hacer para hacer esto? Estoy siguiendo el ejemplo de Jeff Lamarche aquí: Here

¿Es necesario hacer una nueva NSFetchedResultsController y luego configurarlo, o sólo debo hacer una nueva NSFetchRequest y hacer

fetchedResultController.fetchRequest = newFetchRequest 

y luego mi mesa de forma automática ¿actualizar?

Respuesta

31

Me encontré con el mismo problema y pude solucionarlo simplemente configurando los descriptores de clasificación en FetchRequest de FetchRequestController, luego ejecuto una búsqueda (performFetch) y finalmente recargo los datos en la vista de tabla.

NSArray *sortDescriptors = [NSArray arrayWithObject: sorter]; 
[[fetchedResultsController fetchRequest] setSortDescriptors:sortDescriptors]; 
NSError *error; 
if (![[self fetchedResultsController] performFetch:&error]) { 
     // Handle you error here 
} 
[sorter release]; 
[myTableView reloadData]; 

Esta era la forma más fácil para mí tratar con el cambio de la clasificación sobre la marcha sin dejar caer el FRC o realizar cualquier otra manipulación de objetos de lujo. No estoy seguro acerca de las implicaciones de rendimiento en eso y podría tener un impacto si el conjunto de filas en la tabla es enorme.

+0

Utilicé su solución. Parece que no tiene retraso. Pero, ¿algún cuerpo sabe si esto hará una búsqueda física de la base de datos? – user523234

+1

Tenga en cuenta que cambiar sortDescriptors en FreachRequest instanciada de FRC tiene una desventaja. Al usar el método de delegado 'controller: didChangeObject: atIndexPath: forChangeType: newIndexPath:' FRC informa el objeto como 'movido' en vez de 'actualizado' cuando, como dice el documento, 'el atributo cambiado en el objeto es uno de los descriptores de clasificación utilizados en el buscar solicitud'. FRC toma nota de esas rutas de acceso clave solo en su creación de instancias, por lo tanto, cuando más tarde cambie sortDescriptors a otras rutas de acceso de clave, FRC no lo tendrá en cuenta e informará de 'actualizaciones' en lugar de 'movimientos' o viceversa. Mejor hacer un nuevo FRC. – bteapot

2

fetchRequest es una propiedad de solo lectura. La línea de código en tu publicación no funcionará. Si desea utilizar una solicitud de búsqueda diferente, deberá reemplazar su controlador con un nuevo NSFetchedResultsController. Su mesa no se volverá a cargar automáticamente. Tendrá que enviar un mensaje de reloadData después de reemplazar el NSFetchedResultsController.

+7

Aunque no puede crear reemplazar la propiedad fetchRequest del NSFetchedResultsController (es de solo lectura), PUEDE cambiar las propiedades de fetchRequest y volver a buscar. Esto le evita tener que volver a crear NSFetchedResultsController. –

+0

¿Hay alguna posibilidad de cambiar el sectionNameKeyPath sin crear un nuevo NSFetchedResultsController? – ComSubVie

+0

El 'sectionNameKeyPath' es una propiedad de solo lectura, así que creo que necesitarías crear un nuevo' NSFetchedResultsController'. – Alex

8

En lugar de usar NSFetchedResultsController como fuente de datos de la vista de tabla, cree un NSArray que configure cuando el usuario cambie el orden con su control segmentado basándose en los contenidos de la matriz en los resultados obtenidos. Luego solo ordena usando la ordenación de matriz estándar. Algo como esto:

- (IBAction)segmentChanged:(id)sender 
{ 
    // Determine which segment is selected and then set this 
    // variable accordingly 
    BOOL ascending = ([sender selectedSegmentIndex] == 0); 

    NSArray *allObjects = [fetchedResultsController fetchedObjects]; 

    NSSortDescriptor *sortNameDescriptor = 
         [[[NSSortDescriptor alloc] initWithKey:@"name" 
           ascending:ascending] autorelease]; 

    NSArray *sortDescriptors = [[[NSArray alloc] 
        initWithObjects:sortNameDescriptor, nil] autorelease]; 

    // items is a synthesized ivar that we use as the table view 
    // data source. 
    [self setItems:[allObjects sortedArrayUsingDescriptors:sortDescriptors]]; 

    // Tell the tableview to reload. 
    [itemsTableView reloadData];  
} 

Así que el descriptor de clase que he utilizado se llama "nombre", pero que iba a cambiar esto con el nombre del campo que desea ordenar en los resultados inverosímiles. Además, los elementos a los que he hecho referencia serían su nueva fuente de datos de la vista de tabla. Sus delegados vista tabla ahora sería algo como esto:

- (NSInteger)tableView:(UITableView*)tableView 
numberOfRowsInSection:(NSInteger)section 
{ 
    return [items count]; 
} 

- (UITableViewCell *)tableView:(UITableView *)tableView 
     cellForRowAtIndexPath:(NSIndexPath *)indexPath 
{ 
    // Get your table cell by reuse identifier as usual and then grab one of 
    // your records based on the index path 
    // ... 

    MyManagedObject *object = [items objectAtIndex:[indexPath row]]; 

    // Set your cell label text or whatever you want 
    // with one of the managed object's fields. 
    // ... 

    return cell; 
} 

No estoy seguro si esta es la mejor manera, pero debería funcionar.

+0

Este método funciona realmente bien. Gracias Matt. – Dimitris

+1

Con el riesgo de ser un optimizador prematuro: ¿Esto dejaría de ser práctico después de un cierto número de elementos? Si se indiza, la base de datos sería mucho más eficiente en la clasificación. – TimCinel

+0

Esto también es muy útil cuando se necesita ordenar en una propiedad transitoria (que NSFetchedResultsController no hará) – RunLoop

3

La respuesta de Andreas Schaefer funcionó para mí. El truco está estableciendo un nuevo parámetro para la solicitud de búsqueda con el hecho de que es este código:

[[fetchedResultsController fetchRequest] setSortDescriptors:sortDescriptors]; 

O

[[fetchedResultsController fetchRequest] setPredicate:predicate]; 

Antes de llamar a esto:

if (![[self fetchedResultsController] performFetch:&error]) { 
     // Handle you error here 
} 

[self.tableView reloadData]; 

parece que cuando se establece un nuevo parámetro, que NSFetchedResultsController realizará una nueva búsqueda de fetch en función de lo que establezca. Sin establecer un nuevo parámetro, no realizará la recuperación y simplemente llamará al performFetch no funcionará ..

Espero que esto ayude a alguien más ..

+1

Gracias, funcionó perfectamente para mí. Upvoted .. – NSPratik

Cuestiones relacionadas