3

Until now (Swift 2.2) I have been happily using the code from this answer - it's swifty, it's elegant, it worked like a dream.

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
        }
    }
}

Swift 3 changes everything.

Using the code migration tool and Proposal SE- 0006 - sort() => sorted(), sortInPlace() => sort() - I have gotten as far as

extension MutableCollection where Index : Strideable, Iterator.Element : AnyObject {
    /// Sort `self` in-place using criteria stored in a NSSortDescriptors array
    public mutating func sort(sortDescriptors theSortDescs: [SortDescriptor]) {
        sort {
            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: [SortDescriptor]) -> [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
        }
    }
}

The 'sorted' function compiles [and works] without problems. For 'sort' I get an error on the line that says 'sort' : "Cannot convert value of type '(_, _) -> _' to expected argument type '[SortDescriptor]'" which has me completely baffled: I do not understand where the compiler is trying to convert anything since I am passing in an array of SortDescriptors, which ought to BE an array of SortDescriptors.

Usually, this type of error means that you're handling optionals where you ought to have definite values, but since this is a function argument - and seems to work without a hitch in func sorted - all I can read from it is that 'something is wrong'. As of now, I have no idea WHAT that something is, and since we're in the early stages of beta, there is no documentation at all.

As a workaround, I have removed the sort (formerly sort-in-place) function from my code and replaced it with a dance of

let sortedArray = oldArray(sorted[...] oldArray = sortedArray

but I'd be really grateful if I could get my sort-in-place functionality back.

3
  • Why not just something along the likes of (array as NSArray).sortedArray(using: sortDescriptors)? There's nothing wrong with bridging to Foundation types where they provide the functionality you need. Commented Jun 16, 2016 at 16:08
  • a) I prefer to avoid bridging particularly since there's a chance that toll-free bridging will go away at some point. (We already see that tendency). Also, b) I have a method that will work, so this isn't urgent; but I would like to understand what is going on here - I'm missing something, and I can't see it by myself. Commented Jun 16, 2016 at 18:13
  • Can you provide an example of how you used these methods in Swift 2.2? Commented Jun 16, 2016 at 20:36

4 Answers 4

1

Compare the methods available in Swift 2.2:

enter image description here

with the methods in Swift 3:

enter image description here

Notice that Swift 3 does not have a sort method that accepts an isOrderedBefore closure.

That is why your function won't compile.

This looks like a bug, so I reported it as bug 26857748 at bugreport.apple.com.

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

4 Comments

Where did you find those methods? In Xcode 8, I am getting only getting the isOrderedBefore variant in code completion. (sort and sorted in playgrounds, both iOS and MacOS; sorted only in MacOS project). The sorted(sortDescriptors:) variant is available for NSArray in a MacOS project, but not in a playground file.
The above is from an iOS playground file in Xcode 8.
Apple says the method is now sort(by:) but I cannot find this method on MutableCollection. It seems only to exist on EmptyCollection<Element> and CollectionOfOne<Element>.
Attempting to call sort on a MutableCollection results in the error: 'sort' has been renamed to 'sorted(by:)'. But this method returns a new array, it does not sort in place.
0

let sortedArray = users.sorted { $0.name < $1.name }

1 Comment

The OP wants to sort in place, not create a new array.
0

Use RandomAccessCollection protocol

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
        }
    }
}

Comments

0

In Swift 3.0

let sortedCapitalArray = yourArray.sorted {($0 as AnyObject).localizedCaseInsensitiveCompare(($1 as AnyObject)as! String) == ComparisonResult.orderedAscending}

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.