18

I am using coredata so I need sort descriptors for my entities

For example, a Coordinate-entity has this class func:

class func sortDescriptors() -> Array<NSSortDescriptor>
{
    return [NSSortDescriptor(key: "sequence", ascending: true)]
}

I am using this when doing fetch-requests to CoreData like this:

var request = NSFetchRequest(entityName: entityName)

request.sortDescriptors = T.sortDescriptors()

However, when I have an array of coordinates as a property on another coredata object, this is an NSSet (I.e. unsorted)

To solve this, I am returning the coordinates like this:

return NSArray(array: coordinates!).sortedArrayUsingDescriptors(Coordinate.sortDescriptors()) as? Array<Coordinate>

Which feels ugly, to use an NSArray just to get the sortedArrayUsingDescriptors-method. Is there a similar way to do this directly on a Swift-array, I.e. Array<Coordinate> by using sort descriptors?

Thank you!

3
  • 1
    Why don't you use NSSet's sortedArrayUsingDescriptors() method? Commented Nov 12, 2014 at 9:40
  • I could do that aswell! But the question still stands; is sort sescriptors compatible with Swift-arrays? Commented Nov 12, 2014 at 13:52
  • @rintaro NSSet instances are unordered by definition. I assume that you are referring to NSArray. Commented Aug 24, 2015 at 13:56

4 Answers 4

20

Another approach to the nice extensions of Damien could be a multi-cast.

myArray = (myArray as NSArray).sortedArrayUsingDescriptors(tableView.sortDescriptors) as! Array

Original source: NSHipster

Sign up to request clarification or add additional context in comments.

Comments

10

There is no built-in method for this, but you can add them using protocol extension:

extension MutableCollectionType where Index : RandomAccessIndexType, Generator.Element : AnyObject {
    /// Sort `self` in-place using criteria stored in a NSSortDescriptors array
    public mutating func sortInPlace(sortDescriptors theSortDescs: [NSSortDescriptor]) {
        sortInPlace {
            for sortDesc in theSortDescs {
                switch sortDesc.compareObject($0, toObject: $1) {
                case .OrderedAscending: return true
                case .OrderedDescending: return false
                case .OrderedSame: continue
                }
            }
            return false
        }
    }
}

extension SequenceType where Generator.Element : AnyObject {
    /// Return an `Array` containing the sorted elements of `source`
    /// using criteria stored in a NSSortDescriptors array.
    @warn_unused_result
    public func sort(sortDescriptors theSortDescs: [NSSortDescriptor]) -> [Self.Generator.Element] {
        return sort {
            for sortDesc in theSortDescs {
                switch sortDesc.compareObject($0, toObject: $1) {
                case .OrderedAscending: return true
                case .OrderedDescending: return false
                case .OrderedSame: continue
                }
            }
            return false
        }
    }
}

But note that this will work only when the array elements are classes, not structures, as NSSortDescriptor compareObject method requires arguments conforming to AnyObject

1 Comment

Big kudos to you! This was a mind-freaking issue for me. Thanks for helping me out.
8

Swift 3 Version of @Darniel's answer

extension MutableCollection where Self : RandomAccessCollection {
    /// Sort `self` in-place using criteria stored in a NSSortDescriptors array
    public mutating func sort(sortDescriptors theSortDescs: [NSSortDescriptor]) {
        sort { by:
            for sortDesc in theSortDescs {
                switch sortDesc.compare($0, to: $1) {
                case .orderedAscending: return true
                case .orderedDescending: return false
                case .orderedSame: continue
                }
            }
            return false
        }

    }
}

extension Sequence where Iterator.Element : AnyObject {
    /// Return an `Array` containing the sorted elements of `source`
    /// using criteria stored in a NSSortDescriptors array.

    public func sorted(sortDescriptors theSortDescs: [NSSortDescriptor]) -> [Self.Iterator.Element] {
        return sorted {
            for sortDesc in theSortDescs {
                switch sortDesc.compare($0, to: $1) {
                case .orderedAscending: return true
                case .orderedDescending: return false
                case .orderedSame: continue
                }
            }
            return false
        }
    }
}

Comments

1

Swift 5 example

let sortDescriptors: [SortDescriptor<MerchUnitDataRow>] = [SortDescriptor(\MerchUnitDataRow.storeCode, order: .forward),
                                                                     SortDescriptor(\MerchUnitDataRow.storeLevelNumber, order: .forward),
                                                                     SortDescriptor(\MerchUnitDataRow.fixtureNumber, order: .forward)]
        
        let rowData = data.sorted(using: sortDescriptors)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.