2

How can I loop over an array of AnyObjects in Swift and downcast to the appropriate class at the same time? I can do it verbosely like this, but I just can't seem to find a way to do this without an "if let" inside the loop:

func tableView(tableView: NSTableView, sortDescriptorsDidChange oldDescriptors: [AnyObject]) {
    var currentSort = tableView.sortDescriptors
    for s in currentSort {
        if let ss = s as? NSSortDescriptor {
            println("keyPath: \(ss.key()), ascending: \(ss.ascending)")
        }
    }
}

I'm trying to implement sorting for an array of custom objects which is the data source for an NSTableView.

Thanks.

1 Answer 1

6

If the array of [AnyObject] is supposed to be entirely composed of the type you want, you can do a en-mass cast:

func tableView(tableView: NSTableView, sortDescriptorsDidChange oldDescriptors: [AnyObject]) {
    let currentSort = tableView.sortDescriptors as? [NSSortDescriptor]
    for s in currentSort ?? [] {
        println("keyPath: \(s.key()), ascending: \(s.ascending)")
    }
}

This uses [] to substitute an empty array for the nil you get if it turns out one or more of the AnyObject were not of the right type – you’d still need an if…else if you wanted explicit error handling rather than silent failure.

Alternatively if you want your program to trap in case of failure, you could use as! but then it’s a bit of a shame if you find this out in production.

By the way, if the fact that you have to come up with a new name for the unwrapped value was part of what was bothering you, you can just give it the same name:

let x: Int? = 1
if let x = x {
    println(x)
}

which declares a local unwrapped x which masks the outer x within the if.

If some but not all might be of the right type and you only want to operate on those, mapSome is a handy array extension to have around:

extension Array {
    func mapSome<U>(transform: T->U?) -> [U] {
        return lazy(self).map(transform)
            .filter { $0 != nil }
            .map { $0! }.array
    }
}

func tableView(tableView: NSTableView, sortDescriptorsDidChange oldDescriptors: [AnyObject]) {
    let currentSort = tableView.sortDescriptors.mapSome { $0 as? NSSortDescriptor }
    for s in currentSort {
        println("keyPath: \(s.key()), ascending: \(s.ascending)")
    }
}
Sign up to request clarification or add additional context in comments.

1 Comment

Thank you. That about covers it. A VERY thorough answer indeed!

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.