Can an [AnyObject] array be optionally downcast to a type-specific array?

24,746

Solution 1

You've got it -- it works exactly like your example code:

let strings = ["Hi", "Hello", "Aloha"]
let anyObjects: [AnyObject] = strings

if let downcastStrings = anyObjects as? [String] {
    println("It's a [String]")
}
// console says "It's a [String]"

No idea about performance, but I wouldn't assume that it will have to iterate through the full array to determine if a downcast is possible.


So I got curious, and ran a quick test with 100,000 simple values in a couple different [AnyObject] configurations, where I'm trying to downcast the array to a [String] vs. downcasting the individual elements:

// var anyObjects: [AnyObject] = [AnyObject]()
// filled with random assortment of Int, String, Double, Bool
Running test with mixed array
downcast array execution time = 0.000522
downcast elements execution time = 0.571749

// var actuallyStrings: [AnyObject] = [AnyObject]()
// filled with String values
Running test with all strings
downcast array execution time = 1.141267
downcast elements execution time = 0.853765

It looks like it's super fast to dismiss the mixed array as non-downcastable, since it just needs to scan until it finds a non-String element. For an array that it can downcast, it clearly has to crunch through the whole array, and takes much longer, although I'm not sure why it's not the same speed as looping through the array and manually checking each element.

Solution 2

Let's try this

var someObjects = [
    NSString(),
    NSUUID()
]
let uuids = someObjects as? NSUUID[]

uuids is nil

var someOtherObjects = [
    NSUUID(),
    NSUUID()
]
let all_uuids = someOtherObjects as? NSUUID[]

all_uuids is equal to someOtherObjects

So it looks like it does work. You can use the expression to test if all elements of the array are of the expected type but it will not filter the array to select only the expected type.

Share:
24,746

Related videos on Youtube

nhgrif
Author by

nhgrif

Updated on July 09, 2022

Comments

  • nhgrif
    nhgrif almost 2 years

    I'm reading through the Swift documentation, looking at the section regarding type casting.

    The documentation talks about getting an array of type [AnyObject] from Foundation frameworks stuff (what would be an NSArray * in Objective-C).

    First, the documentation provides this example:

    for object in someObjects {
        let movie = object as Movie
        println("Movie: '\(movie.name)', dir. \(movie.director)")
    }
    

    Now, I want to change the example slightly, to a case where I don't know all the objects are of type Movie, so I'd do this:

    for object in someObject {
        if let movie = object as? Movie {
            println("Movie: '\(movie.name', dir. \(movie.director)")
        }
    }
    

    The documentation then provides an example of a better way to write the first loop:

    for movie in someObjects as [Movie] {
       println("Movie: '\(movie.name)', dir. \(movie.director)")
    }
    

    Where we downcast someObjects from an [AnyObject] to a [Movie] so we don't have to downcast within the loop.

    And this got me thinking, can the array be option downcast as a whole?

    if let someMovies = someObjects as? [Movie] {
        for movie in someMovies {
            println("Movie: '\(movie.name)', dir. \(movie.director)")
        }
    }
    

    Does this work? And if so, how bad is this from a performance standpoint? How long would it take to check the type of every object in a 10,000 element array using the optional downcast?

    I understand that the implications between this snippet and my previous optional downcast snippet are different. The first will iterate through every object and only attempt to print if the object is a Movie, where the second will only enter the loop if the array can be downcast to a [Movie] array, in which case it will either print all or none, but I can imagine there are situations where this would be preferable.

  • nhgrif
    nhgrif almost 10 years
    Right, I didn't expect it to filter the array. I am curious as to how this works from a performance point of view in particularly large arrays.
  • voidref
    voidref almost 10 years
    I think the speed difference is because when you are downcasting something, it actually makes a copy of that thing with the other type, and the large allocation is probably taking some time. When allocating one thing at a time, it can use the same small bit of memory over and over again. Try using the profiler, and let us know what it says!