6

Desidero fornire un ordinamento personalizzato utilizzando NSFetchedResultsController e NSSortDescriptor.Ordinamento personalizzato con NSFetchedResultController (sottoclasse NSSortDescriptor)

Come ordinamento personalizzato tramite messaggio NSSortDescriptor - (id) initWithKey: in ordine crescente: selettore: non è possibile (vedi here), ho cercato di usare una classe derivata NSSortDescriptor al fine di ignorare il compareObject: ToObject: messaggio.

Il mio problema è che compareObject: toObject: non viene sempre chiamato. Sembra che sia chiamato solo quando i dati sono già in memoria. Esiste un'ottimizzazione di qualche tipo che utilizza un ordinamento basato su database invece di compareObject: toObject quando i dati vengono recuperati dal negozio la prima volta. (vedi here).

La mia domanda è: come forzare NSFetchedResultscontroller per utilizzare il confrontoObject: toObject: messaggio per ordinare i dati? (e funzionerà con un grande set di dati)

Una soluzione è utilizzare un archivio binario invece di un negozio SQLite, ma non voglio farlo.

Un'altra soluzione è:
-call performFetch per ordinare i dati tramite SQL (compareObject non chiamato)
-fare una modifica ai dati e invertirla.
-call Eseguire nuovamente il recupero (compareOggetto è chiamato)
Funziona nel mio caso ma è un trucco e non sono sicuro che funzionerà sempre (soprattutto con un set di dati di grandi dimensioni (maggiore della dimensione del batch)).

AGGIORNATO: È possibile riprodurre con l'esempio CoreDataBooks.
In RootViewController.m, aggiungere questo brutto hack:

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

In RootViewController.m, sostituire il codice descrittore tipo con:

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

Aggiungi classe 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

Come si sta tentando di ordinare i dati che NSSortDescriptor o una combinazione di più NSSortDescriptors è insufficiente? – ImHuntingWabbits

+0

Sto cercando di ordinare i punti in base alla loro distanza da un punto di riferimento. Speravo di incapsulare il punto di riferimento come un ivar in un oggetto derivato NSSortDescriptor. – FKDev

+0

Hmm, sembra un problema interessante. Sicuramente sembra che dovrai mettere gli oggetti in memoria per ordinarli. Potresti avere una proprietà "referencePoint" sulla tua entità target e una proprietà transitoria chiamata distance. Implementare la distanza per calcolare la distanza tra il punto di riferimento e l'entità di destinazione, ordinare sulla distanza. Anche se mi piace di più la tua idea di sottoclasse. – ImHuntingWabbits

risposta

6

In riferimento alla tua domanda e ai commenti. Dovrai inserire gli oggetti in memoria per ordinarli. Una volta che sono in memoria, è possibile utilizzare un metodo di convenienza per determinare la distanza da un punto.

Per ridurre il numero di oggetti estratti in memoria, è possibile calcolare i valori massimi e minimi e filtrarli, riducendo il raggio della ricerca prima di ordinare.

Non è possibile ordinare su un valore calcolato a meno che non sia in memoria.

+0

Significa che non posso avere i benefici dell'uso della combo UITableViewController + NSFetchedResultsController se voglio fornire un algoritmo di ordinamento personalizzato. – FKDev

+1

non è possibile * solo * utilizzare un 'NSFetchedResultsController' se si sta tentando di ordinare i dati transitori di qualsiasi modulo. Non è l'algoritmo che è il problema, ma i dati. Puoi ancora guardare il contesto con un 'NSFetchedResultsController' o qualche altra forma di watcher (come' ZSContextWatcher') ma dovrai lavorare dopo che gli oggetti sono stati caricati in memoria. –

+0

Beh, posso fare quello che voglio se utilizzo un archivio binario invece dello store SQLite. Peccato, Apple non fornisce un modo per fare l'ordinamento personalizzato per gli sviluppatori che comprendono il compromesso in termini di prestazioni. – FKDev