6

Deseo proporcionar una clasificación personalizada utilizando NSFetchedResultsController y NSSortDescriptor.Clasificación personalizada con NSFetchedResultController (subclase de NSSortDescriptor)

Como costumbre de clasificación a través de mensaje NSSortDescriptor - (id) initWithKey: ascendente: selector: no es posible (ver here), He intentado utilizar una clase derivada NSSortDescriptor con el fin de anular el compareObject: toObject: mensaje.

Mi problema es que compareObject: toObject: no siempre se llama. Parece que se llama solo cuando los datos ya están en la memoria. Existe una optimización de algún tipo que utiliza una ordenación basada en la base de datos en lugar de compareObject: toObject cuando los datos se recuperan de la tienda la primera vez. (ver here).

Mi pregunta es: ¿cómo obligar a NSFetchedResultscontroller a usar el objeto compareObject: toObject: para ordenar los datos? (y ¿funcionará con un gran conjunto de datos)

Una solución es utilizar una tienda binaria en lugar de una tienda sqlite, pero no quiero hacer eso.

Otra solución es:
-call performFetch para ordenar los datos a través de SQL (compareObject no llama)
-hacer una modificación de los datos e invertirla.
-call performRegreso nuevamente (compare se llama Objeto)
Funciona en mi caso, pero es un truco y no estoy seguro de que siempre funcione (especialmente con un gran conjunto de datos (mayor que el tamaño del lote)).

ACTUALIZADO: Puede reproducir con el ejemplo de CoreDataBooks.
En RootViewController.m, anadir este feo truco:

- (void)viewWillAppear:(BOOL)animated { 
    Book* book = (Book *)[NSEntityDescription insertNewObjectForEntityForName:@"Book" 
       inManagedObjectContext:[self fetchedResultsController].managedObjectContext]; 
    [[self fetchedResultsController] performFetch:nil]; 
    [[self fetchedResultsController].managedObjectContext deleteObject:book]; 
    [self.tableView reloadData]; 
} 

En RootViewController.m, reemplace el código descriptor de género con:

MySortDescriptor *myDescriptor = [[MySortDescriptor alloc] init]; 
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:myDescriptor, nil]; 
[fetchRequest setSortDescriptors:sortDescriptors]; 

Añadir clase MySortDescriptor:

@implementation MySortDescriptor 

-(id)init 
{ 
    if (self = [super initWithKey:@"title" ascending:YES selector:@selector(compare:)]) 
    { 

    } 
    return self; 
} 

- (NSComparisonResult)compareObject:(id)object1 toObject:(id)object2 
{ 
    //set a breakpoint here 
    return [[object1 valueForKey:@"author" ] localizedCaseInsensitiveCompare:[object2 valueForKey:@"author" ] ]; 
} 

//various overrides inspired by [this blog post][3] 
- (id)copy 
{ 
    return [self copyWithZone:nil ]; 
} 
- (id)mutableCopy 
{ 
    return [self copyWithZone:nil ]; 
} 
- (id)mutableCopyWithZone:(NSZone *)zone 
{ 
    return [self copyWithZone:zone ]; 
} 
- (id)copyWithZone:(NSZone*)zone 
{ 
    return [[MySortDescriptor alloc] initWithKey:[self key] ascending:[self ascending] selector:[self selector]]; 
} 
- (id)reversedSortDescriptor 
{ 
    return [[[MySortDescriptor alloc] initWithKey:[self key] ascending:![self ascending] selector:[self selector]] autorelease]; 
} 
@end 
+0

¿Cómo está tratando de ordenar sus datos que NSSortDescriptor, o alguna combinación de múltiples NSSortDescriptors es insuficiente? – ImHuntingWabbits

+0

Estoy tratando de ordenar puntos según su distancia desde un punto de referencia. Esperaba encapsular el punto de referencia como un ivar en un objeto derivado NSSortDescriptor. – FKDev

+0

Hmm, eso suena como un problema interesante. Ciertamente parece que tendrás que tirar de los objetos en la memoria para ordenarlos. Podría tener un "punto de referencia" de propiedad en su entidad objetivo y una propiedad transitoria llamada distancia. Implementa la distancia para calcular la distancia entre el punto de referencia y la entidad objetivo, ordena la distancia. Aunque me gusta más tu idea de subclase. – ImHuntingWabbits

Respuesta

6

En referencia a su pregunta y los comentarios. Tendrá que tirar de los objetos a la memoria para ordenarlos. Una vez que están en la memoria, puede usar un método de conveniencia para determinar la distancia desde un punto.

Para disminuir el número de objetos que extrae en la memoria, puede calcular los valores máximo y mínimo y luego filtrarlos, reduciendo el radio de su búsqueda antes de ordenar.

No es posible ordenar en un valor calculado a menos que esté en la memoria.

+0

Significa que no puedo obtener los beneficios de usar el combo UITableViewController + NSFetchedResultsController si deseo proporcionar un algoritmo de ordenación personalizado. – FKDev

+1

no puede * solo * usar un 'NSFetchedResultsController' si está tratando de ordenar los datos transitorios de cualquier forma. El problema no es el algoritmo sino los datos. Todavía puede ver el contexto con un 'NSFetchedResultsController' u otra forma de vigilante (como' ZSContextWatcher') pero tendrá que trabajar una vez que los objetos se carguen en la memoria. –

+0

Bueno, puedo hacer lo que quiero si utilizo una tienda binaria en lugar de la tienda SQLite. Es una lástima, Apple no proporciona una forma de hacer una clasificación personalizada para el desarrollador que entienda la compensación en términos de rendimiento. – FKDev

Cuestiones relacionadas