2015-05-31 12 views
6

Pracuję nad aplikacją na iOS i mam dane przechowywane w CoreData, które ładuję do UITableView. Obiekty danych mają atrybut o nazwie id, który jest ciągiem zawierającym A, po którym następuje liczba (np. "A1" "A2" itp.).NSSortDescriptor w Swift

Kiedy używam tego kodu do sortowania, I skończyć z tabeli są klasyfikowane leksykograficznie (czyli "A1", "A10" "A11" "A12", "A2", "A3" etc)

let sortDescriptor = NSSortDescriptor(key: "id", ascending: true) 
fetchRequest.sortDescriptors = [sortDescriptor] 

Tym, czego naprawdę chcę, jest sortowanie numeryczne, jak można się spodziewać. Jak mam to zrobić? Wiem, że NSComparator może być dodany jako argument do NSSortDescriptor, ale nie mogę dla mojego życia zorientować się. Z góry dziękuję za pomoc!

Odpowiedz

10

Deskryptory sortowania w zapytaniu bazowym (opartym na bazach SQLite) nie mogą używać niestandardowych komparatorów i ograniczonego zestawu "wbudowanych" metod porównywania . Jest to udokumentowane w Fetch Predicates and Sort Descriptors w „Podręczniku programowania danych Core”:

... sklepu SQL, z drugiej strony, kompiluje predykat i sortować deskryptorów SQL i ocenia wynik w samej bazy danych . Robi się to głównie z myślą o wydajności, ale oznacza to, że ocena odbywa się w środowisku innym niż Cocoa, a więc deskryptory sortowania (lub predykaty ), które bazują na kakao, nie mogą działać. Obsługiwane sort selektory są compare: i caseInsensitiveCompare:, localizedCompare:, localizedCaseInsensitiveCompare: i localizedStandardCompare: (The Finder ostatni jest podobny do sortowania, i to, co większość ludzi powinna korzystać z większości czasu). Ponadto nie można sortować właściwości przejściowych przy użyciu magazynu SQLite.

Na szczęście jest jeden, który powinien pasować do Twoich potrzeb:

let sortDescriptor = NSSortDescriptor(key: "id", ascending: true, 
         selector: "localizedStandardCompare:") 

localizedStandardCompare: robi „Finder-like” porównanie i w szczególności traktuje ciągi cyfr w zależności od ich wartości liczbowej.

Dla Swift 2.2/Xcode 7.3 i później:

let sortDescriptor = NSSortDescriptor(key: "id", ascending: true 
         selector: #selector(NSString.localizedStandardCompare)) 
+0

Dokładnie to, czego potrzebowałem. Dziękuję Ci! –

+0

nowy format wydaje się być .. NSSortDescriptor (klucz: "id", rosnąco: true, selector: #selector (NSString.localizedCompare (_ :))) –

+0

@JosephAstrahan: Dzięki, zaktualizowany! –

1

Swifty sposób:

var arr = ["A1", "A10", "A11", "A12", "A2", "A3"] 
arr.sort {dropFirst($0).toInt() < dropFirst($1).toInt()} 

Więc można użyć bezpośrednio, lub używać go jako podstawy dla bloku komparatora. Jeśli nalegasz na zrobienie tego w efektywnym Objective-C, możesz użyć NSString compare:options:, gdzie options: to NSNumericSearch.

+2

Pozwoliłoby to posortować dane * po * pobraniu, ale nie jako deskryptor sortowania w żądaniu pobierania danych podstawowych. –

0

Swift 3

let sortDescriptor = NSSortDescriptor(key: "id", ascending: true, selector: #selector(NSString.localizedCaseInsensitiveCompare))

nadzieję, że pomoże

0

Dla Swift3

kluczem jest

result: Bool = 0 < "string1".localizedCompare("string2").rawValue 

Zastosowanie jak ten

[some string array].sorted { return 0 < "string1".localizedCompare("string2").rawValue } 
0

Dlaczego warto przejmować obj-c styl na NSSortDescriptor, w Swift możemy ładnie porządek używając Swift funkcje wysokiej zamówienie - Xcode 8.x Swift 3.x

class Person: NSObject { 
    let firstName: String 
    let lastName: String 
    let age: Int 

    init(firstName: String, lastName: String, age: Int) { 
     self.firstName = firstName 
     self.lastName = lastName 
     self.age = age 
    } 
    override var description: String { 
     return "\(firstName) \(lastName)" 
    } 
} 

let a = Person(firstName: "a", lastName: "b", age: 24) 
let b = Person(firstName: "c", lastName: "d", age: 27) 
let c = Person(firstName: "e", lastName: "f", age: 33) 
let d = Person(firstName: "g", lastName: "h", age: 31) 
let peopleObject = [d, b, a, c] 
//SWIFTY 
let sortedByFirstNameSwifty = peopleObject.sorted(by: { $0.firstName < $1.firstName }) 
print(sortedByFirstNameSwifty)//prints[a b, c d, e f, g h] 


//Objective c way 
let firstNameSortDescriptor = NSSortDescriptor(key: "firstName", ascending: true, selector: #selector(NSString.localizedStandardCompare(_:))) 
let sortedByFirstName = (peopleObject as NSArray).sortedArray(using: [firstNameSortDescriptor]) 
print(sortedByFirstName)//prints [a b, c d, e f, g h]