8

Obecnie próbuję wypełnić UITableView w moim projekcie z danych podstawowych przy użyciu NSFetchedResultsController. Używam wyszukiwanie niestandardowe z komparatora (choć Próbowałem również selektor i miał identyczny problem):NSFetchedResultsController sortowanie niestandardowe nie otrzymuje nazwę

if (fetchedResultsController != nil) { 
     return fetchedResultsController; 
    } 

    /* 
    Set up the fetched results controller. 
    */ 
    // Create the fetch request for the entity. 
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init]; 
    // Edit the entity name as appropriate. 
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"Object" inManagedObjectContext:self.managedObjectContext]; 
    [fetchRequest setEntity:entity]; 

    // Set the batch size to a suitable number. 
    [fetchRequest setFetchBatchSize:20]; 
    NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"objectName" ascending:YES comparator:^(id s1, id s2) { 
      NSLog(@"Comparator"); 
     //custom compare here with print statement 
    }]; 
    NSLog(@"Sort Descriptor Set"); 
    NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil]; 
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"Object" inManagedObjectContext:self.managedObjectContext]; 
    [fetchRequest setEntity:entity]; 
    [fetchRequest setSortDescriptors:sortDescriptors]; 

    NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:@"firstLetterOfObject" cacheName:@"Objects"]; 
    [aFetchedResultsController release]; 
    [fetchRequest release]; 
    [sortDescriptor release]; 
    [sortDescriptors release]; 
    if (![fetchedResultsController performFetch:&error]) { 
     NSLog(@"Unresolved error %@, %@", error, [error userInfo]); 
     abort(); 
    } 

    return fetchedResultsController; 

Kiedy wprowadzić tę kartę, mam zalogowany całego programu i okazało się, że NSFetchedResultsController robi nie wchodzić nawet do bloku komparatora podczas pobierania. Zamiast tego sortuje go za pomocą domyślnej metody sortowania.

Jeśli usuwam i dodaję obiekt o nazwie objectName, wówczas należy wprowadzić blok porównawczy i poprawnie posortować tabelę.

Dlaczego NSFetchedResultsController nie sortuje przy użyciu komparatora, dopóki nie zostanie zmieniony zarządzany model obiektu?

Uwagi: Próbowałem również wyłączyć buforowanie i/lub wykonać pobranie w viewDidLoad :, ale wydaje się, że ile razy pobieram nie ma znaczenia, ale kiedy. Z jakiegoś powodu używa tylko mojego sortowania po zmianie modelu obiektu.

Odpowiedz

8

Istnieje kilka rzeczy Mogę myśleć o. Po pierwsze, chociaż nie jest to Twój problem, nie możesz sortować właściwości przejściowych. Ale bardziej prawdopodobne jest to, że podczas sortowania w modelu wspieranym przez magazyn SQL komparator jest "kompilowany" do zapytania SQL, a nie wszystkie funkcje Objective-C są dostępne. W takim przypadku musisz sortować w pamięci po wykonaniu pobierania.

EDYCJA: Zobacz tę doc, w szczególności sekcję Predykaty pobierania i sortowania sortowania.

+1

Nie są to właściwości przejściowe, ale twoja druga sugestia zdecydowanie wydaje się być problemem. Jedynym problemem jest to, że polegam na kontrolce fetchedresult, aby podać nazwy sekcji i tak do widoku tabeli, więc sortowanie w pamięci za każdym razem byłoby trudne (myślę). Jak poleciłbyś, abyś to zrobił? Moje drugie pytanie brzmi: dlaczego blok porównawczy działa po zmianie modelu obiektu? Dziękuję Ci! –

+0

Tak naprawdę bardziej ogólny problem polega na tym, że implementuję sekcje w widoku tabeli wraz z indeksem sekcji. Umieszczam dowolny obiekt zaczynający się od numeru w sekcji "123" (działa to), ale chcę, aby ta sekcja znajdowała się na dole, tak jak w przypadku aplikacji na iPoda. Według aplikacji Apple numery powinny być ostatnią opcją w sectionIndex (używam UILocalizedIndexedCollation do generowania indeksów sekcji). Wydaje się jednak, że nie ma sposobu, aby pobrać sekcje, aby liczby były ostatnie. Czy znasz bardziej wiarygodny sposób na to niż niestandardowe sortowanie? –

+2

Po prostu zgaduję, ale myślę, że blok porównawczy działa po zmianie modelu obiektu, ponieważ wykres jest już w pamięci. Ale to tylko domysły. Uważam, że sposób ręcznego sortowania polega na podklasie NSArrayController, więc utracisz zalety NSFetchedResultsController. Ale, jak mówisz, głównym problemem jest to, że chcesz posortować liczby na sam dół.Z góry mojej głowy, powiedziałbym, utworzyć właściwość porządku sortowania na twoich obiektach i użyć tego, ale nie zrobiłem wystarczająco dużo niestandardowego sortowania za pomocą deskryptorów sortowania. – Don

0

Niestety, ale nie przegapisz ostateczny sprowadzić części do fragmentu kodu ?:

NSError *error; 
BOOL success = [aFetchedResultsController performFetch:&error]; 

Nie zapomnij zwolnić wniosek TOO:

[fetchRequest release]; 
+0

Nie, po prostu nie uwzględniłem tego w opisie. Zawarłem całą metodę, jeśli to czyni ją bardziej zrozumiałą. –

1

Widzę ten sam problem i sposób obejścia go polega na modyfikacji obiektu, zapisaniu zmiany, przywróceniu jej pierwotnej wartości i ponownym zapisaniu.

// try to force an update for correct initial sorting bug 
NSInteger count = [self.fetchedResultsController.sections count]; 
if (count > 0) { 
    id <NSFetchedResultsSectionInfo> sectionInfo = [[self.fetchedResultsController sections] objectAtIndex:0]; 
    count = [sectionInfo numberOfObjects]; 
    if (count > 0) { 
     NSManagedObject *obj = [self.fetchedResultsController objectAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]]; 
     NSString *name = [obj valueForKey:@"name"]; 
     [obj setValue:@"X" forKey:@"name"]; 
     // Save the context. 
     [self saveContext]; 
     [obj setValue:name forKey:@"name"]; 
     // Save the context. 
     [self saveContext]; 
    } 
}