NSSortDescriptor in Swift

I am working on an iOS application and I have data stored in CoreData which I load into a UITableView. Entities have an id attribute, which is a string containing A followed by a number (for example, “A1”, “A2”, etc.).

When I use this code to sort, I end up sorting the table lexicographically (i.e. "A1" "A10" "A11" "A12" "A2" "A3", etc.)

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

I really want it to be sorted numerically, as you would expect. How can I do it? I know that a NSComparator can be added as an argument to NSSortDescriptor , but I have not been able to understand it throughout my life. Thanks in advance for your help!

+8
source share
7 answers

Sort descriptors in a SQLite-based Core Data query cannot use custom comparators and only a limited set of "built-in" comparisons. This is documented in Retrieve Predicates and Sort Descriptors in the Master Data Programming Guide:

... SQL repository, on the other hand, compiles the predicate and sorts the SQL descriptors and evaluates the result in the database itself. This is done primarily for performance, but it means that the evaluation takes place in an environment without cocoa, and therefore sorting handles (or predicates) that rely on cocoa cannot work. Supported sorting by selectors are compare: and caseInsensitiveCompare: localizedCompare: localizedCaseInsensitiveCompare: and localizedStandardCompare: (the latter is sorting like Finder, and that most people should use most of the time). In addition, you cannot sort transient properties using SQLite repository.

Fortunately, there is one that should fit your needs:

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

localizedStandardCompare: makes a comparison of the type "Finder" and, in particular, processes the numbers in the lines according to their numerical value.

For Swift 2.2 / Xcode 7.3 and later:

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

The swifty way:

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

That way you can use this directly or use it as the basis for a block for your comparator. If you insist on doing this effectively with Objective-C, you can use NSString compare:options: where options: enable NSNumericSearch .

+1
source

Swift 3

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

hope this helps

0
source

For Swift3

key

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

Use it as

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

Why worry about the obj-c NSSortDescriptor , In fast we can nicely sort using Swift quick-order functions - 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[ab, cd, ef, gh] //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 [ab, cd, ef, gh] 
0
source

for quick 4.2

You can sort the array using NSSortDescriptor

 let descriptor: NSSortDescriptor = NSSortDescriptor(key: "lastMessageDate", ascending: false) let sortedResults = arrChatDialogs?.sortedArray(using: [descriptor]) 
0
source

You can sort the collection of objects using the default sorted function as follows:

for example your array of objects looks like

 data = [ { name: "Naresh", dept: "CSC", id: 102 }, { name: "Rahul", dept: "CSC", id: 101 }, { name: "Amar", dept: "CSC", id: 100 } ] //Comparing string key let sortByName = data.sorted { (model1, model2) -> Bool in return (model1.name.localizedCompare(model2.name) == ComparisonResult.orderedAscending) } /* The ComaprisonResult is default enum whose possible cases are: */ public enum ComparisonResult : Int { case orderedAscending case orderedSame case orderedDescending } /*** SORTING ACCORDING TO NUMERICAL VALUE ***/ //Comparing digit key including Int, Double, Float & all let sortByNumber = data.sorted { (model1, model2) -> Bool in return model1.id < model2.id } //You can use the shot form of automatic closure as: let sortByNumber = data.sorted { $0.id > $1.id } //In the autoclosure the $0 represent first parameter, $1 represent second parameter. The return statement is optional if closure or functions contains only single statement. 
0
source

Source: https://habr.com/ru/post/988254/


All Articles