2

I'm having trouble sorting an array of strings. The array i'm trying to sort derives from all of the keys in an NSMutableDictionary. I think my main problem is that the keys of value "AnyObject" and that's interfering with my sort function. Here is what I've tried so far:

    var sections = self.sortedFriends.allKeys

Attempt 1

    sort(&sections) {$0 < $1}

Attempt 2

    self.sectionTitles = sections.sorted({ (str1:NSString, str2:NSString) -> Bool in
                    return str1 < str2
                })

I keep getting the error "AnyObject is not a subtype of NSString". In Objective-C it was easy to use the caseInsensitiveCompare function, but that no longer seems to be the case. If someone can help me I'd appreciate it. Thanks!

2 Answers 2

4

You need to turn your [AnyObject] into things that can actually be compared. You can either do it at the point of fetching the keys:

// as? will return nil if any of the keys are not Strings, this substitutes
// an empty array in that case - you may want different handling
var sections = (self.sortedFriends.allKeys as? [String]) ?? []

or cast each element individually:

// here, if an individual key is not a String, as? will 
// return nil.  nil is always < non-nil
sort(&sections) { ($0 as? String) < ($1 as? String) }

The benefit of the latter is it can handle if one individual element isn't a String – the as? will return nil and nil is always less than non-nil so your non-string values will group up one end.

With strings specifically, there's one other option:

// with the as? String version above, 5 would come before "4"
let nsm = [3:"4", 2:5] as NSMutableDictionary
var sections = nsm.allValues
// but in this case, both are converted to strings and sort correctly
sort(&sections) { toString($0) < toString($1) }
Sign up to request clarification or add additional context in comments.

2 Comments

This worked as well, but I chose the other answer for its simplicity. Thanks for the input!
One problem I am having with the sort(&sections) { ($0 as? String) < ($1 as? String) } method is that i'm getting the error "NSArray does not conform to MutableCollectionType". The same error occurs with NSMutableArray
3

Try casting it to strings because right now, it's really an array of type [NSObject]. Since there's no overload for the < operator that accepts NSObject, it doesn't know what to do.

let sorted = (dict.allKeys as? [String])?.sorted(<)

3 Comments

@user3353890 unfortunately that simplicity is hiding a nasty potential bug – if there are ever any non-String keys, this will explode at runtime with an assertion – try let nsd = ["Bob":1, 5:2] as NSDictionary; let keys = nsd.allKeys as [String]. In fact, in the 1.2 beta, this kind of as was renamed to as! to indicate it’s dangerous and probably best avoided.
@AirspeedVelocity Ick, yeah that doesn't sound good. The way the rest of my code is written however, there shouldn't be any non string keys included in the dictionary. I see what you are saying though, thanks for the insight! I'll most likely change my code just to be safe
This answer now accounts for all possible nil errors or cast fails.

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.