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.
Downcasting. A constant or variable of a certain class type may actually refer to an instance of a subclass behind the scenes. Where you believe this is the case, you can try to downcast to the subclass type with a type cast operator ( as? or as! ).
Downcasting is the opposite of upcasting, and it refers to casting an object of a parent class type to an object of its children class. Downcasting is used to reconvert objects of a children class that were upcasted earlier to generalize.
To validate the type of an instance 'Type Casting' comes into play in Swift 4 language. It is used to check whether the instance type belongs to a particular super class or subclass or it is defined in its own hierarchy.
Operator. Prior to Swift 1.2, the as operator could be used to carry out two different kinds of conversion, depending on the type of expression being converted and the type it was being converted to: Guaranteed conversion of a value of one type to another, whose success can be verified by the Swift compiler.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With