7

Mam zestaw obiektów encji w mojej bazie danych Core iOS, które opisują coś w lokalizacji. Nazwijmy obiekt Lokalizacja. Wdrożyłem to poprzez posiadanie dwóch atrybutów w lokalizacji, które odnoszą się do lokalizacji - szerokości i długości geograficznej, zarówno dwójkowych. Istnieją inne elementy, takie jak imię.Lokalizacje w danych podstawowych posortowane według odległości za pomocą NSFetchedResultsController?

Używam NSFetchedResultsController do wiązania elementów do UITableViewController. Chciałbym, aby wyniki były sortowane według odległości do danego CLLocationCoordinate2D. W naprawdę idealnym scenariuszu mogę odświeżyć tę listę, aby przeliczyć sortowanie na podstawie nowej lokalizacji. W związku z tym ten rodzaj zależy od dwóch kluczy i trzeciej "statycznej" zmiennej (takiej, która nie różni się w zależności od pozycji w kolekcji).

Myślę, że mógłbym dowiedzieć się, jak to zrobić, jeśli sortowałem dowolną listę z NSSortDescriptors. Nie kontroluję jednak, w jaki sposób deskryptory sortowania używane są w NSFetchedResultsController.

Czy istnieje sposób, aby skonfigurować moje jednostki, mój NSFetchedResultsController, moje NSSortDescriptors itp., Aby to osiągnąć? Podejrzewam, że odpowiedź nie polega na stworzeniu fantazyjnego NSSortDescriptor, lecz na utworzeniu przejściowego atrybutu w jednostce, która reprezentuje odległość do mnie i okresowej rekalkulacji tego atrybutu. Jednak jestem wystarczająco nowy w Core Data, że ​​nie jestem pewien, jak najlepiej to zrobić (powtórzenie wszystkich obiektów i ponowne obliczenie pola). Nie jestem również pewien, czy NSSortDescriptors będzie działać na atrybutach Transient.

+0

Niestety, pobrany kontroler wyników nie może sortować atrybutów przejściowych lub właściwości obliczonych. Zobacz http://stackoverflow.com/questions/13292582/nspredicate-with-function-not-working lub http://stackoverflow.com/questions/12027769/nssortdescriptor-sort-by-location dla podobnych zagadnień i odniesień do dokumentacja. –

+0

Dziękujemy! Widziałem to i dlatego pomyślałem, że odpowiedź może polegać na obliczaniu wartości w moich jednostkach podstawowych danych. Zdejmijmy Transient z tabeli - jeśli to nie jest pole przejściowe, w jaki sposób chciałbym okresowo aktualizować zestaw encji? –

+0

Czy naprawdę potrzebujesz kontrolera pobranych wyników? Jeśli pobierzesz obiekty do tablicy, możesz posortować ją w pamięci i użyć jako źródła danych dla widoku tabeli. –

Odpowiedz

12

(Od komentarzach :)

FETCH wniosek o (SQLite) z siedzibą sklepu Rdzeń danych nie można wykorzystać deskryptory sortowania na podstawie przejściowych atrybutów lub Objective-C orzeczników bazie.

Jeśli nie chcesz tracić przewagi pobieranego kontrolera wyników (np. Animowane aktualizacje widoku tabeli, automatyczne grupowanie w sekcje itp.) Musisz wstępnie obliczyć odległość do bieżącej lokalizacji i zapisać ją w (trwałe) atrybut twoich obiektów.

Można również pobrać wszystkie obiekty i posortować je w pamięci. W takim przypadku możesz użyć dowolnych deskryptorów sortowania. Ale nie można tego połączyć z pobranym kontrolerem wyników, więc należy zarejestrować się w celu zmiany kontekstu obiektu zarządzanego iw razie potrzeby ponownie załadować tabelę.

0

Odkryłem BSFetchedResultsController github project, który jest podklasą NSFetchResultsController, która robi to, co sugerował Martin, sortuje w pamięci przy użyciu dowolnego deskryptora sortowania, ponadto rejestruje również zmiany w kontekście i oblicza wszelkie zmiany indeksu ponownie biorąc pod uwagę arbitralne sort deskryptora. W sumie bardzo imponujący wyczyn! I z powodzeniem stosować go do sortowania według odległości następująco:

BSFetchedResultsController* fetchedResultsController = [[BSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:managedObjectContext sectionNameKeyPath:nil cacheName:nil]; 

// create a location to compare distance to, e.g. current location 
CLLocation* sourceLocation = [[CLLocation alloc] initWithLatitude:55.87595153937809 longitude:-4.2578177698913855]; 

// compare the distance from both to the source location 
fetchedResultsController.postFetchComparator= ^(id a, id b) { 
    Venue* v1 = (Venue*)a; 
    Venue* v2 = (Venue*)b; 

    double d1 = [v1.coreLocation distanceFromLocation:sourceLocation]; 
    double d2 = [v2.coreLocation distanceFromLocation:sourceLocation]; 

    return [@(d1) compare:@(d2)]; 
}; 

NSError *error = nil; 
if (![fetchedResultsController performFetch:&error]) { 
    NSLog(@"Unresolved error %@, %@", error, [error userInfo]); 
} 

Od swojego starego projektu nie ma łuku, więc kiedy to dwa pliki pamiętać aby zaznaczyć .m z kompilatora Flagi -fno-objc -Koniec w Celu, Fazy Budowania. Pamiętaj też, że programista uważa, że ​​kod nie jest gotowy do produkcji, więc upewnij się, że wykonałeś odpowiednie testy, jeśli go używasz.

W powyższym kodzie mam przejściową właściwość coreLocation na podklasie obiektów zarządzanych obiektów Venue, można zobaczyć, jak osiągnąć to here. Również obliczenie odległości jest nieefektywne, możesz chcieć buforować odległość w obiekcie, zamiast przeliczać ją ponownie przy każdym porównaniu.

Wreszcie wydaje się, projekt ten stał się z powodu twórcy Daniela Thorpe'a Stackoverflow pytanie będzie bez odpowiedzi, zmuszając go, aby rozwiązać ten problem i pisać tylko odpowiedzieć sobie, więc myślę, że jeśli znajdziesz swój projekt przydatnych mogłeś uprzejmie up-vote his post tak, jak ja zrobiłem.

Powiązane problemy